J'ai une table avec des informations de commande dans un magasin de commerce électronique. Schéma ressemble à ceci:
[commandes]
ID | Sous-total | Taxamount | LivraisonAmount | DateCreated P>
Ce tableau ne contient que des données pour chaque commande. Donc, si une journée passe sans ordre, aucune donnée de vente n'est là pour ce jour-là. Strong> P> J'aimerais sélectionner sous-total-par jour pendant les 30 derniers jours, y compris ces jours-ci avec Pas de vente. P> Les ResulatsSet ressembleraient à ceci: p> date | Salessum Faire cela, ne me donne que des données pour ces jours avec des commandes: p> Vous pouvez créer une table appelée dates, puis sélectionner. table et rejoindre la table des commandes. Mais je veux vraiment éviter cela, car cela ne fonctionne pas assez bien lorsqu'il s'agit de différentes fuseaux horaires et des choses ... P> S'il vous plaît ne riez pas. SQL n'est pas mon genre de chose ... :) p> p>
2009-08-01 | 15235
2009-08-02 | 0
2009-08-03 | 340
2009-08-04 | 0
... p>
9 Réponses :
declare @oldest_date datetime
declare @daily_sum numeric(18,2)
declare @temp table(
sales_date datetime,
sales_sum numeric(18,2)
)
select @oldest_date = dateadd(day,-30,getdate())
while @oldest_date <= getdate()
begin
set @daily_sum = (select sum(SubTotal) from SalesTable where DateCreated = @oldest_date)
insert into @temp(sales_date, sales_sum) values(@oldest_date, @daily_sum)
set @oldest_date = dateadd(day,1,@oldest_date)
end
select * from @temp
OK - I missed that 'last 30 days' part. The bit above, while not as clean, IMHO, as the date table, should work. Another variant would be to use the while loop to fill a temp table just with the last 30 days and do a left outer join with the result of my original query.
Il suffit d'ajouter une clause où des 30 derniers jours
Cela n'inclut aucun jour qui ne dispose pas de ventes (comme demandé à l'origine)
Si cela était juste que c'est facile :) J'ai besoin de tous les jours pendant les 30 derniers jours.
OK - Ce bit n'est pas bien testé, mais cela devrait fonctionner. Sinon, ce n'est pas loin.
SELECT DateCreated, SUM(SubTotal) AS SalesSum FROM Orders GROUP BY DateCreated
y compris ces jours sans vente. P> blockQuote>
C'est la partie difficile. Je ne pense pas que la première réponse vous aidera avec ça. J'ai fait quelque chose de similaire à celui-ci avec une table de date distincte. p>
Vous pouvez trouver les instructions sur la façon de le faire ici: P>
En fait, j'étais sous l'hypothèse que les jours sans ventes ne seraient pas dans la table. Sinon, ne pas tenir compte de ma réponse.
Ce n'est pas le cas. La table ne contient que des données par commande. Donc, si une journée passe sans ordres, aucune donnée de vente n'est là pour ce jour-là.
Ensuite, je créerais une table de date avec toutes les dates et ensuite faire une joindre à une requête qui résumerait les ventes par jour. Vous vous souviendriez également d'utiliser une déclaration de coalesce pour revenir à zéro au lieu de NULL pendant des jours sans ventes. J'ai dû le faire dans de nombreuses situations différentes et la table de date externe était la voie à suivre.
J'ai vu des moments où cette table des dates a mal des dattes, des numéros de semaine et des choses. Je veux vraiment éviter cela.
Eh bien, si vous n'utilisez pas une table contenant toutes les dates de votre période, vous saurez les dates où il n'y a pas de vente. Vous obtiendrez: 2009-08-01 | 15235 2009-08-03 | 340 Le script est bien documenté et facile à comprendre, mais écrit pour T-SQL. Je pense toujours que c'est la voie à suivre.
Il possède certains des numéros de semaine et différentes fuseaux horaires, temps d'économie de jour, etc.
Créer une fonction pouvant générer un tableau de date comme suit: puis rejoindre ce tableau p>
(volé de http://www.codeproject.com/kb/database/generateAtetable.aspx )
Avec une déléguement sélectionnée légèrement modifiée, cela fonctionne: Sélectionnez Dates.Date, ISNULL (Somme (CommandesBtotal), 0) en tant que ventes de [DOFTABLE] ('2009-08-01', '2009-08-31' , 'Day') Datesleft Rejoignez les commandes sur Convert (varchar (10), ordres.datecreated, 111) = dates.dategroup par dates.date
J'ai mis à jour la deuxième requête. J'ai eu le champ de date incorrect dans le groupe Select / Group par, de sorte que la limitée à des dates uniquement avec les ventes. J'ai testé cette version et je pense que cela donne ce que vous voulez. Il a des nuls au lieu de 0 à 0 à des jours sans ventes, mais vous pouvez facilement utiliser la fonction de regroupement pour essuyer ceux-ci.
Je ne peux pas obtenir cela pour travailler pour le fromage. Quelqu'un peut-il me montrer la réponse correcte exacte?
Je l'ai fait aujourd'hui. Nous avons également reçu une demande de commerce électronique. Je ne veux pas remplir notre base de données avec des dates "inutiles". Je viens de faire le groupe et de créer tous les jours pour les N jours de Java, et je les regarde avec les résultats de la date / des ventes de la base de données. p>
Où est-ce que cela va finalement se retrouver? Je ne demande que parce qu'il est peut-être plus facile de remplir les journées vides avec tout le programme va traiter des données au lieu d'essayer de le faire en SQL. P>
SQL est une langue merveilleuse et elle est capable d'avoir beaucoup de choses, mais parfois, vous préférez bien travailler les points finers des données dans le programme. P>
J'ai une table de table de journal avec logid un index que je n'ai jamais supprimé d'enregistrements. Il a indice de 1 à ~ 10000000. Utilisation de ce tableau, je peux écrire
select
s.ddate, SUM(isnull(o.SubTotal,0))
from
(
select
cast(datediff(d,LogID,getdate()) as datetime) AS ddate
from
Log
where
LogID <31
) s right join orders o on o.orderdate = s.ddate
group by s.ddate
(révisé un peu - je frappe une entrée trop tôt)
J'ai commencé à piquer à ce sujet, et comme il frappe de jolis concepts SQL difficiles, il a rapidement grandi dans le monstre suivant. Si possible, vous risquez peut-être mieux de vous adapter à la solution. Ou, comme beaucoup d'autres conseils, l'utilisation du code d'application pour combler les lacunes pourrait être préférable. p> étape 1 est de construire une table Temp contenant les 30 dates que vous concernez avec. Que l'abstraite est la solution la plus rapide connue pour construire une table d'entiers consécutifs; Ajoutez quelques plus de sous-requêtes et vous pouvez peupler des millions ou plus en quelques secondes. Je prends les 30 premiers et utilisez DaadDD et la date / heure actuelle pour les convertir en dates. Si vous avez déjà une table "fixe" qui contient 1-30, vous pouvez l'utiliser et sauter le CTE entièrement (en remplaçant le tableau "Tally" avec votre table). P> Les appels de fonction de DATE OUTER DATE Supprimer la partie de temps de la chaîne générée. p> (Notez que je suppose que la date de votre commande n'a pas non plus de temps de temps - sinon vous avez un autre problème courant à résoudre.) P> Pour des raisons de test, j'ai construit des #orders de table, et cela vous obtient le reste: p>
Ceci est basé sur SQL Server 2005, dans lequel des expressions de table communes (que laids «avec« clause ») ont été introduites. Il existe d'autres moyens d'obtenir ces résultats, mais la CTE est la plus rapide pour les bâtiments de table Tally ad hoc.
J'ai créé la fonction daettable comme JamesMlv m'a signalé.
puis le SQL ressemble à ceci: p>
Qu'est-ce que vous utilisez? Les réponses peuvent varier si vous utilisez MySQL ou SQL Server, ou quelque chose d'autre ...