SQL - How do I join multiple tables and add appropriately with SUM? - sql-server

I'm trying to join multiple tables (Microsoft SQL Server Management Studio v.18.9.1) together (based on an ID) and have it SUM out a new column using a sum aggregate. Here are my tables:
Table: California
CaliforniaID
Name
AmountCalifornia
C1
Alan
1.00
C1
Alan
1.00
C1
Alan
1.00
C1
Alan
2.00
C2
Eric
2.00
C2
Eric
2.00
C2
Eric
3.00
C3
Janero
3.00
C3
Janero
3.00
C3
Janero
5.00
Table: Texas
TexasID
Name
AmountTexas
T2
Eric
2.01
T2
Eric
2.01
T2
Eric
2.01
T3
Jan
3.01
T3
Jan
3.01
T4
Lil
4.01
Table: Florida
FloridaID
Name
AmountFlorida
F5
Manny
10.00
F5
Manny
10.00
F6
Nina
11.00
F3
Jan
100.00
F4
Lily
27.00
Table Junction1 that I created to be able to Join any tables that I need to in the future
All of the respective IDs match, so that I have something to join by
CaliforniaID
TexasID
FloridaID
Name
C1
T1
F1
Alan B.
C2
T2
F2
Eric D.
C3
T3
F3
Janero T.
C4
T4
F4
Lila E.
C5
T5
F5
Manuello R.
C6
T6
F6
Nina H.
C7
T7
F7
Perry R.
C8
T8
F8
Ramos T.
C9
T9
F9
Skye F.
C10
T10
F10
Trinity A.
When I run the following query:
SELECT TOP 10
j.name,
COALESCE(SUM(t.amount1), 0) AS CaliforniaExpenses,
COALESCE(SUM(t.amount2), 0) AS TexasExpenses,
COALESCE(SUM(t.amount1), 0) + COALESCE(SUM(t.amount2), 0) AS TotalExpenses
FROM
junction1 j
LEFT JOIN
(SELECT
CaliforniaID, null AS TexasID,
AmountCalifornia AS amount1, null AS amount2
FROM
test1
UNION ALL
SELECT
null, TexasID, null, AmountTexas
FROM
test2) t ON t.CaliforniaID = j.CaliforniaID
OR t.TexasID = j.TexasID
GROUP BY
j.name
ORDER BY
CaliforniaExpenses DESC;
Result
Name
CaliforniaExpenses
TexasExpenses
TotalExpenses
Janero T.
11.00
6.02
17.02
Eric D.
7.00
6.03
13.03
Alan B.
5.00
0.00
5.00
Trinity A.
0.00
0.00
0.00
Skye F.
0.00
0.00
0.00
Ramos T.
0.00
0.00
0.00
Perry R.
0.00
0.00
0.00
Nina H.
0.00
0.00
0.00
Manuello R.
0.00
0.00
0.00
Lila E.
0.00
33.06
33.06
Which is great so far! Is there any possible way to sneak in the Florida column FloridaExpenses (right after the TexasExpenses Alias) and have the total reflected for it as well?
Any help is greatly appreciated!

Step 1. Aggregate each State's Expenses table to ID level.
Step 2. Left outer join from Junction1 to the other three on ID column
with
cte_ca as (select CaliforniaID, sum(AmountCalifornia) as AmountCalifornia from California group by CaliforniaID),
cte_tx as (select TexasID, sum(AmountTexas) as AmountTexas from Texas group by TexasID),
cte_fl as (select FloridaID, sum(AmountFlorida) as AmountFlorida from Florida group by FloridaID)
select j.Name,
coalesce(sum(ca.AmountCalifornia),0) as CaliforniaExpenses,
coalesce(sum(tx.AmountTexas),0) as TexasExpenses,
coalesce(sum(fl.AmountFlorida),0) as FloridaExpenses,
coalesce(sum(ca.AmountCalifornia),0) + coalesce(sum(tx.AmountTexas),0) + coalesce(sum(fl.AmountFlorida),0) as TotalExpenses
from Junction1 j
left
join cte_ca ca on j.CaliforniaID = ca.CaliforniaID
left
join cte_tx tx on j.TexasID = tx.TexasID
left
join cte_fl fl on j.FloridaID = fl.FloridaID
group by j.name
order by j.name;
Outcome:
Name |CaliforniaExpenses|TexasExpenses|FloridaExpenses|TotalExpenses|
-----------+------------------+-------------+---------------+-------------+
Alan B. | 5.0000| 0.0000| 0.0000| 5.0000|
Eric D. | 7.0000| 6.0300| 0.0000| 13.0300|
Janero T. | 11.0000| 6.0200| 100.0000| 117.0200|
Lila E. | 0.0000| 4.0100| 27.0000| 31.0100|
Manuello R.| 0.0000| 0.0000| 20.0000| 20.0000|
Nina H. | 0.0000| 0.0000| 11.0000| 11.0000|
Perry R. | 0.0000| 0.0000| 0.0000| 0.0000|
Ramos T. | 0.0000| 0.0000| 0.0000| 0.0000|
Skye F. | 0.0000| 0.0000| 0.0000| 0.0000|
Trinity A. | 0.0000| 0.0000| 0.0000| 0.0000|
db<>fiddle

Related

How to group multiple occurrences by sign, count and show the date of occurrence from to

How to group multiple occurrences by sign, count and show the date of occurrence from to .
Each group of code occurrences interrupted by another code is to be shown separately.
All my attempts fail...
thanks for the help in advance
Table
date sign Value
2022-10-01 C 6.00
2022-10-02 C 6.00
2022-10-03 C 6.00
2022-10-04 W 8.00
2022-10-05 W 8.00
2022-10-06 W 8.00
2022-10-07 W 8.00
2022-10-10 C 8.00
2022-10-11 C 8.00
2022-10-12 C 8.00
2022-10-26 B 8.00
2022-10-27 B 8.00
2022-10-28 Y 8.00
IDEAL OUTPUT
C 2022-10-01 - 2022-10-03 3 18
W 2022-10-04 - 2022-10-07 4 32
C 2022-10-10 - 2022-10-12 3 24
B 2022-10-26 - 2022-10-27 2 16
Y 2022-10-28 - 2022-10-28 1 8
This just needs a standard gaps-and-islands approach. First step is to partition the rows into groups, then you can aggregate:
with gp as (
select *,
Row_Number() over(order by date)
- Row_Number() over(partition by sign order by date) g
from t
)
select Sign, Min(date) FromDate, Max(date) ToDate, Count(*) Qty, Sum(value) Total
from gp
group by Sign, g;
Example DB Fiddle
I'm trying to add the first and last name to the table above.
Big problem is person like John Malk. The sign is to be counted if it occurred in consecutive dates. If it occurs in a different date string, it must be shown separately.
I don't think there is any way to do it like above. Probably need to use a loop ?
Table
name surname date sign Value
John Malk 2022-10-01 C 6.00
John Malk 2022-10-02 C 6.00
John Malk 2022-10-03 C 6.00
John Malk 2022-11-07 C 6.00
Katie Sun 2022-10-04 W 8.00
Katie Sun 2022-10-05 W 8.00
Katie Sun 2022-10-06 W 8.00
Katie Sun 2022-10-07 W 8.00
Jim Folk 2022-10-10 C 8.00
Jim Folk 2022-10-11 C 8.00
Jim Folk 2022-10-12 C 8.00
Arthur Mand 2022-10-26 B 8.00
Arthur Mand 2022-10-27 B 8.00
Ann Kiss 2022-10-28 Y 8.00
Ideal Output
John Malk C 2022-10-01 2022-10-03 3 18
John Malk C 2022-11-07 2022-11-07 1 6
Katie Sun W 2022-10-04 2022-10-07 4 32
Jim Folk C 2022-10-10 2022-10-12 3 24
Arthur Mand B 2022-10-26 2022-10-27 2 16
Ann Kiss Y 2022-10-28 2022-10-28 1 8

How to return a MAX() value without adding all columns to the Group By clause?

Lets Say I have these Four Tables
A
Serial Make Model
A AA 123
B AB 222
C AA 124
B
HeaderID OpenDate Serial
001 1/1/2021 A
002 1/1/2021 B
003 1/2/2021 C
C
HeaderID SegmentID JobCode
001 001 1A
001 002 1B
002 003 2A
D
SegmentID Cost Tax Date
001 $25.00 $2.00 1/1/2021
002 $10.00 $1.00 1/2/2021
003 $15.00 $1.00 1/3/2021
My Code looks like this:
SELECT B.HeaderID, A.Serial, A.Make, A.Model, B.OpenDate, C.JobCode, D.Cost + D.Tax AS TotalCost
FROM B
INNER JOIN
A ON A.Serial = B.Serial
INNER JOIN C
ON C.HeaderID = B.HeaderID
INNER JOIN D
ON D.SegmentID = C.SegmentID
This gives me the result of :
HeaderID Serial Make Model OpenDate JobCode Total Cost
001 A AA 123 1/1/2021 1A $27.00
001 A AA 123 1/1/2021 1B $11.00
002 B AB 222 1/1/2021 2A $16.00
003 C AA 124 1/2/2021 NULL NULL
I am now being asked to bring in the MAX Date from the D table for each HeaderID. So my new results should be:
HeaderID Serial Make Model OpenDate JobCode Cost Date
001 A AA 123 1/1/2021 1A $27.00 1/2/2021
001 A AA 123 1/1/2021 1B $11.00 1/2/2021
002 B AB 222 1/1/2021 2A $16.00 1/3/2021
003 C AA 124 1/2/2021 NULL NULL NULL
Is there an easy way to simply add this on to the existing query that I have without having to start over from the top? Thanks in advance?
Using a CTE like this to get the MAX date, then LEFT joining it back to your original query should work.
;WITH MX
AS (
SELECT HeaderID, MAX([Date]) AS MaxDate
FROM C
INNER JOIN D
ON D.SegmentID = C.SegmentID
GROUP BY HeaderID
)
SELECT B.HeaderID, A.Serial, A.Make, A.Model, B.OpenDate, C.JobCode, D.Cost + D.Tax AS TotalCost, MX.MaxDate
FROM B
INNER JOIN A
ON A.Serial = B.Serial
INNER JOIN C
ON C.HeaderID = B.HeaderID
INNER JOIN D
ON D.SegmentID = C.SegmentID
LEFT JOIN MX
ON D.HeaderID = MX.HeaderID

T-SQL check to see data is in range then select record from table A

Table A
ID name date_from date_to region manager
---------------------------------------------------------
1 Harry 2019-12-01 2020-01-01 south ABC
1 Harry 2020-01-01 2020-03-01 north BCD
1 Harry 2020-03-01 NULL East DCE
Table B
Date name H_time T_time
---------------------------------------
2019-12-01 Harry 30 20
2020-01-01 Harry 20 10
2020-02-01 Harry 40 50
2020-04-01 Harry 50 60
I wanted to check table B date falls into the date range above and return the specific region and manager info like...
Table C
Date name H_time T_time region manager
---------------------------------------------------------
2019-12-01 Harry 30 20 south ABC
2020-01-01 Harry 20 10 north BCD
2020-02-01 Harry 40 50 north BCD
2020-04-01 Harry 50 60 East DCE
You can use a join:
select b.*, a.region, a.manager
from b join
a
on b.name = a.name and
b.date >= a.date_from and
(b.date <= date_to or a.date_to is null);
Based on your expected result, this should do the trick
SELECT b.*, a.region, a.manager
FROM table_b b
INNER JOIN table_a a on b.name = a.name
WHERE
(b.date >= a.date_from and b.date < a.date_to)
OR
(b.date >= a.date_from and a.date_to IS NULL)

What is the correct sql query for this output?

Table1
id name purchase Group
001 vince 26 G1
002 vince 28 G1
002 vince 31 G1
002 vince 38 G2
003 karl 24 G2
003 karl 24 G2
Expected Output
id name Purchase
001 vince 26
002 vince 59
003 karl 0
The question is not very clear, but here is a Query that should work:
SELECT id, name, SUM(CASE WHEN [Group] = 'G1' THEN purchase ELSE 0 END) AS Purchase
FROM Table1
GROUP BY id, name
ORDER BY id

Finding common value in two columns

I have a problem with a query where i need to get all the common values in column #2 that are for every element of column #1.
For example:
Column #1 Column #2
-------------------
21 2.00
21 5.00
21 6.00
21 8.00
21 9.00
41 2.00
41 3.00
41 4.00
41 5.00
41 6.00
41 9.00
52 2.00
52 5.00
52 9.00
52 10.00
52 20.00
Result
-------------------
2.00
5.00
Any help will be greatly appreciated.
Juan Alvarez
SELECT column2
FROM YourTable
GROUP BY column2
HAVING COUNT(*) = (SELECT COUNT(DISTINCT column1) FROM YourTable)

Resources