Reputation: 17
I'm trying to pull back multiple different sums from one table using different criteria. The only problem is that my subqueries were pulling back more than one response, so I changed my query a bit and then got extremely lost trying to find the best way to do this.
Here's the query I'm working with right now:
SELECT TER_ID AS TER_ID,
SUM(MED_AMT) AS NET_SLS_AMT,
SUM(SELECT MED_AMT
FROM DAY_TER_MEDIA
WHERE TND_CD = 1 AND
DAY_TER_MEDIA.DT = '') AS CASH_AMT,
SUM(SELECT MED_AMT
FROM DAY_TER_MEDIA
WHERE DAY_TER_MEDIA.TND_CD IN(4,5,16,18,23,31) AND
DAY_TER_MEDIA.DT = '') AS ELEC_AMT,
SUM(SELECT MED_AMT
FROM DAY_TER_MEDIA
WHERE DAY_TER_MEDIA.TND_CD IN(2,3,8,9,10,11,15,20,52) AND
DAY_TER_MEDIA.DT = '') AS OTHER_AMT
FROM DAY_TER_MEDIA
WHERE DT = ''
GROUP BY TER_ID;
As you can see, my intention is to pull back NET_SLS_AMT, CASH_AMT, ELEC_AMT, and OTHER_AMT all from the same column and sum only those with a certain TND_CD, DT, and TER_ID. As I said, I've been changing this query up multiple times and I know the current iteration of it does not actually do what I need it to. I'm a bit lost as to how to do this while still grouping them all by date and TER_ID. Any ideas? Or is there even a clean way to do this?
Upvotes: 0
Views: 309
Reputation: 5030
One approach is to use a CASE expression to return conditional totals. My example uses the following sample data:
Sample Data
/* Using table variables makes sharing sample data easy.
*/
DECLARE @Example TABLE
(
[Type] INT,
AMT MONEY
)
;
INSERT INTO @Example
(
[Type],
AMT
)
VALUES
(1, 10),
(1, 15),
(1, 45),
(2, 30),
(2, 20)
;
In the example each column conditionally contains the AMT or 0, based on the Type. The SUM function aggregates the results.
Example
/* Removing the SUM functions would highlight how this technique works.
*/
SELECT
SUM(CASE WHEN [Type] = 1 THEN AMT ELSE 0 END) AS AMT_1,
SUM(CASE WHEN [Type] = 2 THEN AMT ELSE 0 END) AS AMT_2
FROM
@Example
;
Upvotes: 0
Reputation: 50019
The reason you are not getting your expected results, is because there is no relationship between your subqueries and the table in your FROM. You would need to add that relationship in each of your subqueries WHERE
clauses (which is called a Correlated Subquery since it uses values from the outer query in the subquery):
SELECT TER_ID AS TER_ID,
SUM(MED_AMT) AS NET_SLS_AMT,
SUM(SELECT MED_AMT
FROM DAY_TER_MEDIA
WHERE TND_CD = 1 AND TER_ID = t1.TER_ID AND
DAY_TER_MEDIA.DT = '') AS CASH_AMT,
SUM(SELECT MED_AMT
FROM DAY_TER_MEDIA
WHERE DAY_TER_MEDIA.TND_CD IN(4,5,16,18,23,31) AND TER_ID = t1.TER_ID AND
DAY_TER_MEDIA.DT = '') AS ELEC_AMT,
SUM(SELECT MED_AMT
FROM DAY_TER_MEDIA
WHERE DAY_TER_MEDIA.TND_CD IN(2,3,8,9,10,11,15,20,52) AND TER_ID = t1.TER_ID AND
DAY_TER_MEDIA.DT = '') AS OTHER_AMT
FROM DAY_TER_MEDIA t1
WHERE DT = ''
GROUP BY TER_ID;
But this is a very inefficient way of doing this. Instead, use CASE
statements without any subqueries:
SELECT
TER_ID,
SUM(CASE WHEN TND_CD = 1 THEN MED_AMT ELSE 0 END) as CASH_AMT,
SUM(CASE WHEN TND_CD IN(4,5,16,18,23,31) THEN MED_AMT ELSE 0 END) as ELEC_AMT,
SUM(CASE WHEN TND_CD IN(2,3,8,9,10,11,15,20,52) THEN MED_AMT ELSE 0 END) AS OTHER_AMT
FROM DAY_TER_MEDIA
WHERE DT= ''
GROUP BY TER_ID
Upvotes: 2
Reputation: 13949
Use case statements instead of selects
SELECT TER_ID AS TER_ID,
SUM(MED_AMT) AS NET_SLS_AMT,
SUM(CASE WHEN TND_CD = 1 THEN MED_AMT
ELSE 0
END) AS CASH_AMT,
SUM(CASE WHEN DAY_TER_MEDIA.TND_CD IN (4,5,16,18,23,31) THEN MED_AMT
ELSE 0
END) AS ELEC_AMT,
SUM(CASE WHEN DAY_TER_MEDIA.TND_CD IN (2,3,8,9,10,11,15,20,52) THEN MED_AMT
ELSE 0
END) AS OTHER_AMT
FROM DAY_TER_MEDIA
WHERE DT = ''
GROUP BY TER_ID;
Upvotes: 1