2017-03-01 6 views
3

J'ai une table qui répertorie l'index/l'ordre, le nom et la valeur. Par exemple, il ressemble à ceci:Valeurs SUM dans SQL à partir d'un point spécifique d'une autre table

TABLE1: 
ID | NAME | VALUE 
1 | A | 2 
2 | B | 5 
3 | C | 2 
4 | D | 7 
5 | E | 0 

Maintenant, j'ai une autre table qui a une liste aléatoire de noms. Cela montrera soit A, B, C, D ou E. Selon ce que le nom est, je voulais calculer la somme de toutes les valeurs qu'il faudra pour arriver à E. Est-ce logique?

Donc, si, par exemple, ma table ressemble à ceci:

TABLE2: 
NAME 
D 
B 
A 

je voudrais une autre colonne à côté du nom qui va montrer la somme. Donc D aurait 7 parce que l'événement suivant est E. B devrait être la somme de 5, 2 et 7 parce que B est 5, et C est 2, et D est 7. Et A aurait la somme de 2, 5, 3 et 7 et ainsi de suite.

Espérons que cela soit facile à comprendre.

En fait, je n'ai pas beaucoup de choses à part joindre les deux tables et obtenir la valeur actuelle du nom. Mais je ne savais pas comment incrémenter et ainsi de suite et continuer à ajouter?

SELECT T2.NAME, T1.VALUE 
FROM Table1 T1 
LEFT JOIN Table2 T2 ON T1.NAME = T2.NAME 

Est-ce possible? Ou est-ce que je perds mon temps? Devrais-je faire référence au code réel pour le faire? Ou devrais-je faire une fonction?

Je ne savais pas par où commencer et j'espérais que quelqu'un pourrait m'aider.

Merci d'avance!

+1

On dirait que vous cherchez une somme en cours; c'est une fonction de fenêtrage normale: voir ceci: https://www.wagonhq.com/blog/running-totals-sql – gregory

Répondre

1

Comme le suggère gregory, vous pouvez le faire avec une fonction fenêtré simple, qui (dans ce cas) résumera toutes les lignes après et y compris l'actuel basé sur la valeur ID. De toute évidence, il y a un certain nombre de façons dont vous pouvez couper vos données, bien que je vais laisser ça à vous d'explorer :)


declare @t table(ID int,Name nvarchar(50),Val int); 
insert into @t values(1,'A',2),(2,'B',5),(3,'C',2),(4,'D',7),(5,'E',0); 

select ID  -- The desc makes the preceding work the right way. This is 
     ,Name -- essentially shorthand for "sum(Val) over (order by ID rows between current row and unbounded following)" 
     ,Val -- which is functionally the same, but a lot more typing... 
     ,sum(Val) over (order by ID desc rows unbounded preceding) as s 
from @t 
order by ID; 

qui sortie:

+----+------+-----+----+ 
| ID | Name | Val | s | 
+----+------+-----+----+ 
| 1 | A | 2 | 16 | 
| 2 | B | 5 | 14 | 
| 3 | C | 2 | 9 | 
| 4 | D | 7 | 7 | 
| 5 | E | 0 | 0 | 
+----+------+-----+----+ 
+0

Wow, celui-ci a très bien fonctionné et ne nécessitait qu'une ligne supplémentaire. Je vais certainement devoir regarder de plus près cette fonction fenêtrée, mais c'est exactement ce que je cherchais. – chakolatemilk

+0

@chakolatemilk Il existe plusieurs façons d'utiliser la classe "over", en particulier avec 'partition' qui regroupe vos données pour fournir les agrégations. Ce sont des ajouts fantastiques à SQL qui permettent d'économiser énormément de données. – iamdave

0
CREATE TABLE #tempTable2(name VARCHAR(1)) 
INSERT INTO #tempTable2(name) 
VALUES('D') 
INSERT INTO #tempTable2(name) 
VALUES('B') 
INSERT INTO #tempTable2(name) 
VALUES('A') 


CREATE TABLE #tempTable(id INT, name VARCHAR(1), value INT) 
INSERT INTO #temptable(id,name,value) 
VALUES(1,'A',2) 
INSERT INTO #temptable(id,name,value) 
VALUES(2,'B',5) 
INSERT INTO #temptable(id,name,value) 
VALUES(3,'C',2) 
INSERT INTO #temptable(id,name,value) 
VALUES(4,'D',7) 
INSERT INTO #temptable(id,name,value) 
VALUES(5,'E',0) 



;WITH x AS 
(
    SELECT id, value, name, RunningTotal = value 
    FROM dbo.#temptable 
    WHERE id = (SELECT MAX(id) FROM #temptable) 

    UNION ALL 

    SELECT y.id, y.value, y.name, x.RunningTotal + y.value 
    FROM x 
     INNER JOIN dbo.#temptable AS y ON 
      y.id = x.id - 1 

) 
SELECT x.id, x.value, x.name, x.RunningTotal 
    FROM x 
    JOIN #tempTable2 t2 ON 
     x.name = t2.name 
    ORDER BY x.id 



DROP TABLE #tempTable 
DROP TABLE #tempTable2 
2

La requête est en deux parties; c'est difficile à voir au début, alors je vais parcourir chaque étape.

Étape 1: Obtenir la somme de roulement

Joignez table1 à lui-même pour les lettres plus que lui-même:

select * 
    from table1 t1 
    inner join table1 t2 on t2.name >= t1.name 
    order by t1.name 

Ce produit le tableau suivant

+ -- + ---- + ----- + -- + ---- + ----- + 
| id | name | value | id | name | value | 
+ -- + ---- + ----- + -- + ---- + ----- + 
| 1 | A | 2  | 1 | A | 2  | 
| 1 | A | 2  | 2 | B | 5  | 
| 1 | A | 2  | 3 | C | 2  | 
| 1 | A | 2  | 4 | D | 7  | 
| 1 | A | 2  | 5 | E | 0  | 
| 2 | B | 5  | 2 | B | 5  | 
| 2 | B | 5  | 3 | C | 2  | 
| 2 | B | 5  | 4 | D | 7  | 
| 2 | B | 5  | 5 | E | 0  | 
| 3 | C | 2  | 3 | C | 2  | 
| 3 | C | 2  | 4 | D | 7  | 
| 3 | C | 2  | 5 | E | 0  | 
| 4 | D | 7  | 4 | D | 7  | 
| 4 | D | 7  | 5 | E | 0  | 
| 5 | E | 0  | 5 | E | 0  | 
+ -- + ---- + ----- + -- + ---- + ----- + 

Notez que si nous groupons par le nom de t1, nous pouvons obtenir la somme roulante en additionnant les valeurs de t2.Cette requête

select t1.name, 
     SUM(t2.value) as SumToE 
    from table1 t1 
    inner join table1 t2 
     on t2.name >= t1.name 
    group by t1.name 

nous donne les sommes de roulement que nous voulons

+ ---- + ------ + 
| name | sumToE | 
+ ---- + ------ + 
| A | 16  | 
| B | 14  | 
| C | 9  | 
| D | 7  | 
| E | 0  | 
+ ---- + ------ + 

Note: Cela équivaut à utiliser une fonction fenêtré qui résume sur un ensemble, mais il est beaucoup plus facile de voir visuellement ce vous faites par cette technique de jonction.

Étape 2: Joignez-vous à la somme de roulement

Maintenant que vous avez cette somme glissante pour chaque lettre, vous joignez simplement à table2 pour les lettres que vous voulez

select t1.* 
    from table2 t2 
    inner join (
     select t1.name, 
       SUM(t2.value) as SumToE 
      from table1 t1 
      inner join table1 t2 
       on t2.name >= t1.name 
      group by t1.name 
    ) t1 on t1.name = t2.name 

Résultat:

+ ---- + ------ + 
| name | sumToE | 
+ ---- + ------ + 
| A | 16  | 
| B | 14  | 
| D | 7  | 
+ ---- + ------ + 
+0

Je vais avoir du mal à suivre ça .. Donc pour la deuxième requête donnée, est-ce que # tab1 est la table qui a été produite dans la première requête? Parce que j'ai essayé la deuxième requête donnée et elle m'a seulement donné le même résultat que Table1 elle-même. Pardon! Pouvez-vous expliquer un peu plus? – chakolatemilk

+0

Désolé à ce sujet. J'utilise des tables temporaires lorsque j'écris mon code, c'est pourquoi la dénomination est différente. Mon # tab1 est votre Table1 et mon # tab2 est votre Table2. Je mettrai à jour ma réponse avec ces changements – KindaTechy