I have a set of data(below) that i am trying to get a pivot out summing the quantity and aggregating the columns with a desired result as shown below. Is there an easy way to do this?
Location1 Location2 Product Mode Customer Quantity
61 151 A TL Bill 800
61 151 A TL Bill 800
61 501 B TL Nan 800
61 501 C TL Cas 800
61 901 B TL Cas 800
61 901 B TL Cas 800
61 111 C TL Bill 800
Desired Result:
Location1 Location2 Product Mode Customer Quantity**
61 151 A TL Bill 1600
61 501 B TL Nan 800
61 501 C TL Cas 800
61 501 C TL Cas 1600
61 111 C TL Bill 800
Since I'm a little bored, i'll do your work for you.
Declare #data as Table(Location1 int, Location2 int, Product varchar(1), Mode varchar(2), Customer varchar(5), Quantity float)
Insert into #data(Location1, Location2, Product, Mode, Customer, Quantity)
Values
(61, 151, 'A', 'TL', 'Bill',800 )
, (61, 151, 'A', 'TL', 'Bill',800 )
, (61, 501, 'B', 'TL', 'Nan',800 )
, (61, 501, 'C', 'TL', 'Cas',800 )
, (61, 901, 'B', 'TL', 'Cas',800 )
, (61, 901, 'B', 'TL', 'Cas',800 )
, (61, 111, 'C', 'TL', 'Bill', 800)
SELECT
Location1, Location2, Product, Mode, Customer, Sum(Quantity) as TotalQty
FROM
#Data
GROUP BY
Location1, Location2, Product, Mode, Customer
ORDER BY
Product
And the Results:
(7 row(s) affected)
Location1 Location2 Product Mode Customer TotalQty
----------- ----------- ------- ---- -------- -----------
61 151 A TL Bill 1600
61 501 B TL Nan 800
61 901 B TL Cas 1600
61 111 C TL Bill 800
61 501 C TL Cas 800
(5 row(s) affected)
Related
I have this table:
CODE
IDNR
NAME
LIMIT
123
80
XXX
2019-05
123
81
XXX
2019-10
124
80
YYY
2019-01
125
80
ZZZ
2019-05
125
81
ZZZ
2019-06
125
80
ZZZ
2019-07
126
80
III
2019-05
126
80
III
2019-09
126
80
III
2019-07
I want to have a new column (Count-LIMIT ) contain how many LIMIT per code, and another contain YES if the limit are continuous and No if not.
MY RESULT that I want like:
CODE
IDNR
NAME
LIMIT
Count-Limit
CON
123
80
XXX
2019-05
2
NO
123
81
XXX
2019-10
2
NO
124
80
YYY
2019-01
1
NO
125
80
ZZZ
2019-05
3
YES
125
81
ZZZ
2019-06
3
YES
125
80
ZZZ
2019-07
3
YES
126
80
III
2019-05
3
NO
126
80
III
2019-09
3
NO
126
80
III
2019-07
3
NO
THANKS!
Try this:
WITH T (CODE, IDNR, NAME, LIMIT) AS
(
VALUES
(123, 80, 'XXX', '2019-05')
, (123, 81, 'XXX', '2019-10')
, (124, 80, 'YYY', '2019-01')
, (125, 80, 'ZZZ', '2019-05')
, (125, 81, 'ZZZ', '2019-06')
, (125, 80, 'ZZZ', '2019-07')
, (126, 80, 'III', '2019-05')
, (126, 80, 'III', '2019-09')
, (126, 80, 'III', '2019-07')
, (128, 80, 'AAA', '2021-01')
, (128, 80, 'AAA', '2021-03')
, (128, 80, 'AAA', '2021-05')
, (128, 80, 'AAA', '2021-07')
, (128, 80, 'AAA', '2021-08')
, (128, 80, 'AAA', '2021-09')
)
SELECT
T.*
, COUNT (1) OVER (PARTITION BY CODE) AS COUNT_LIMIT
, CASE
WHEN TO_DATE (LIMIT || '-01', 'YYYY-MM-DD') IN
(
LAG (TO_DATE (LIMIT || '-01', 'YYYY-MM-DD')) OVER (PARTITION BY CODE ORDER BY LIMIT) + 1 MONTH
, LEAD (TO_DATE (LIMIT || '-01', 'YYYY-MM-DD')) OVER (PARTITION BY CODE ORDER BY LIMIT) - 1 MONTH
)
THEN 'YES'
ELSE 'NO'
END AS CON
FROM T
ORDER BY CODE, LIMIT
The result is:
CODE
IDNR
NAME
LIMIT
COUNT_LIMIT
CON
123
80
XXX
2019-05
2
NO
123
81
XXX
2019-10
2
NO
124
80
YYY
2019-01
1
NO
125
80
ZZZ
2019-05
3
YES
125
81
ZZZ
2019-06
3
YES
125
80
ZZZ
2019-07
3
YES
126
80
III
2019-05
3
NO
126
80
III
2019-07
3
NO
126
80
III
2019-09
3
NO
128
80
AAA
2021-01
6
NO
128
80
AAA
2021-03
6
NO
128
80
AAA
2021-05
6
NO
128
80
AAA
2021-07
6
YES
128
80
AAA
2021-08
6
YES
128
80
AAA
2021-09
6
YES
I have a table with around 80000 records. Here is an example:
startyear
division
account
budget
forecast
2021
40
4100
5122952,22
0,012306656
2022
40
4100
0
0,011424198
2023
40
4100
0
0,010431491
2024
40
4100
0
0,009311863
2025
40
4100
0
0,008324122
2026
40
4100
0
0,007763793
2027
40
4100
0
0,007557735
2028
40
4100
0
0,007357883
2029
40
4100
0
0,007160051
2030
40
4100
0
0,006953345
2031
40
4100
0
0,006737952
2032
40
4100
0
0,006535297
2033
40
4100
0
0,006364179
2034
40
4100
0
0,006213237
2035
40
4100
0
0,006085724
2036
40
4100
0
0,005944279
2037
40
4100
0
0,005758285
2038
40
4100
0
0,005559474
2039
40
4100
0
0,005360105
2040
40
4100
0
0,005163794
2041
40
4100
0
0,004972228
I'm trying to calculate a new column starting with the budget from line 1. So year 2021 will be the same. the first calculation is correct. But the rest of the calculation ignores the changes before.
This is the code:
WITH cte AS (
SELECT startyear, division, account, forecast, SUM(budget) AS asum
FROM #table
GROUP BY startyear,
division,
account,
forecast
), cteRanked AS (
SELECT cte.startyear,
cte.division,
cte.account,
cte.forecast,
cte.asum AS asum
FROM cte
)
SELECT c1.startyear,
c1.division,
c1.account,
c1.forecast,
c1.asum , ISNULL((SELECT SUM(c2.asum)*c1.forecast
FROM cteRanked c2
WHERE c1.startyear > 2021
AND c2.startyear < c1.startyear
AND c2.division = c1.division
AND c2.account = c1.account), c1.asum) AS Bud
FROM cteRanked c1
ORDER BY c1.division, c1.account, c1.startyear
Gives this result:
startyear
division
account
forecast
budget
result
correct
2021
40
4100
0,012306656
5122952,22
5122952,22
5122952,22
2022
40
4100
0,011424198
0
58525,62051
58525,62
2023
40
4100
0,010431491
0
53440,02998
54050,54
2024
40
4100
0,009311863
0
47704,22923
48752,52
2025
40
4100
0,008324122
0
42644,07928
43987,00
2026
40
4100
0,007763793
0
39773,54059
41367,57
As you can see this query does not cumulate the results when the query runs.
Anyone have any ideas?
While your post is lacking some vital information...I don't necessarily blame you because it's a difficult problem to both explain and to solve.
It looks like you're basically trying to come up with a compounding interest calculator. Except in this case, the rate changes every year.
To calculate the PRODUCT aggregate of your forecasts, I found this blog post:
https://blog.jooq.org/2018/09/21/how-to-write-a-multiplication-aggregate-function-in-sql/
It just required a very tiny bit of tweaking.
This is my answer:
DECLARE #StartingYear int = 2021,
#StartingBudget decimal(12, 2);
SELECT #StartingBudget = yt.budget
FROM #YourTable yt
WHERE yt.startyear = #StartingYear
SELECT yt.startyear, yt.division, yt.account, yt.budget, yt.forecast, YearBudget = yt.budget, PrevYearDiff = yt.budget
FROM #YourTable yt
WHERE yt.startyear = #StartingYear
UNION ALL
SELECT x.startyear, x.division, x.account, x.budget, x.forecast
, YearBudget = CONVERT(decimal(10,2), x.SumProdBudget)
, PrevYearDiff = CONVERT(decimal(10,2), x.SumProdBudget - LAG(x.SumProdBudget,1,#StartingBudget) OVER (ORDER BY x.startyear))
FROM (
SELECT yt.startyear, yt.division, yt.account, yt.budget, yt.forecast
, SumProdBudget = EXP(SUM(LOG(1+yt.forecast)) OVER (ORDER BY yt.startyear)) * #StartingBudget
FROM #YourTable yt
WHERE yt.startyear > #StartingYear
) x
Returns:
| startyear | division | account | budget | forecast | YearBudget | PrevYearDiff |
|-----------|----------|---------|------------|-------------|------------|--------------|
| 2021 | 40 | 4100 | 5122952.22 | 0.012306656 | 5122952.22 | 5122952.22 |
| 2022 | 40 | 4100 | 0.00 | 0.011424198 | 5181477.84 | 58525.62 |
| 2023 | 40 | 4100 | 0.00 | 0.010431491 | 5235528.38 | 54050.54 |
| 2024 | 40 | 4100 | 0.00 | 0.009311863 | 5284280.90 | 48752.52 |
| 2025 | 40 | 4100 | 0.00 | 0.008324122 | 5328267.90 | 43987.00 |
| 2026 | 40 | 4100 | 0.00 | 0.007763793 | 5369635.47 | 41367.57 |
The key to this whole thing is this line:
SELECT SumProdBudget = EXP(SUM(LOG(1+yt.forecast)) OVER (ORDER BY yt.startyear)) * #StartingBudget
This is saying to return a running product of all previous forecasts, then multiply that by the original budget. This will produce the budget for each year, technically based on the budget of the previous year.
Then once you have that, I stuck it in a sub-query to find the difference between the year and its previous year.
Sample Data:
IF OBJECT_ID('tempdb..#YourTable','U') IS NOT NULL DROP TABLE #YourTable; --SELECT * FROM #YourTable
CREATE TABLE #YourTable (
startyear int NOT NULL,
division int NOT NULL,
account int NOT NULL,
budget decimal(12, 2) NOT NULL,
forecast decimal(10, 9) NOT NULL,
);
INSERT INTO #YourTable (startyear, division, account, budget, forecast)
VALUES (2021, 40, 4100, 5122952.22, 0.012306656)
, (2022, 40, 4100, 0 , 0.011424198)
, (2023, 40, 4100, 0 , 0.010431491)
, (2024, 40, 4100, 0 , 0.009311863)
, (2025, 40, 4100, 0 , 0.008324122)
, (2026, 40, 4100, 0 , 0.007763793)
, (2027, 40, 4100, 0 , 0.007557735)
, (2028, 40, 4100, 0 , 0.007357883)
, (2029, 40, 4100, 0 , 0.007160051)
, (2030, 40, 4100, 0 , 0.006953345)
, (2031, 40, 4100, 0 , 0.006737952)
, (2032, 40, 4100, 0 , 0.006535297)
, (2033, 40, 4100, 0 , 0.006364179)
, (2034, 40, 4100, 0 , 0.006213237)
, (2035, 40, 4100, 0 , 0.006085724)
, (2036, 40, 4100, 0 , 0.005944279)
, (2037, 40, 4100, 0 , 0.005758285)
, (2038, 40, 4100, 0 , 0.005559474)
, (2039, 40, 4100, 0 , 0.005360105)
, (2040, 40, 4100, 0 , 0.005163794)
, (2041, 40, 4100, 0 , 0.004972228);
I have this data:
Start End Quantity
425 449 24
450 474 24
475 499 24
500 524 24
2300 2324 24
2400 2499 99
2500 2599 99
2800 2899 99
2900 2999 99
3200 3249 49
3250 3299 49
3300 3349 49
3350 3399 49
3400 3449 49
3500 3549 49
3600 3624 24
3650 3674 24
3700 3724 24
3950 3964 14
4000 4000 0
4150 4399 249
4400 4499 99
5034 5075 41
Quantity is a result of End - Start.
I would like to obtain the following data, the Generated rows:
Start End Quantity
425 449 24
450 474 24
475 499 24
500 524 24
425 524 96
2300 2324 24
2300 2324 24
2400 2499 99
2500 2599 99
-----GENERATED----
425 2599 438
------------------
2800 2899 99
2900 2999 99
3200 3249 49
3250 3299 49
3300 3349 49
3350 3399 49
3400 3449 49
3500 3549 49
-----GENERATED-----
2800 3549 492
------------------
3600 3624 24
3650 3674 24
3700 3724 24
3950 3964 14
4000 4000 0
4150 4399 249
4400 4499 99
5034 5075 41
-----GENERATED-----
3600 5075 475
------------------
The condition is that it has to sum all the quantities until 500. If it passes 500 do a new count.
I have tried with Rollup but I couldnt find the right condition to make it work.
Of course, this is way easier to do by programming code instead of SQL, but we must do it in database environment. The tools to get the generated rows can be anything, looping functions, new tables etc.
Error solving
I got into an error while running #Prdp's query:
Msg 530, Level 16, State 1, Line 1
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
I found the solution here:
http://sqlhints.com/tag/the-statement-terminated-the-maximum-recursion-100-has-been-exhausted-before-statement-completion/
Update 1
Using #Prdp's query we got the following:
Start End rn st
(400) 424 1 24
425 449 2 48
450 474 3 72
475 499 4 96
500 524 5 120
2300 2324 6 144
2400 2499 7 243
2500 2599 8 342
2800 (2899) 9 (441)
(2900) 2999 10 99
3200 3249 11 148
3250 3299 12 197
3300 3349 13 246
3350 3399 14 295
3400 3449 15 344
3500 3549 16 393
3600 3624 17 417
3650 3674 18 441
3700 3724 19 465
3950 3964 20 479
4000 (4000) 21 (479)
(4150) 4399 22 249
4400 4499 23 348
5034 (5075) 24 (389)
Its getting closer to what we need. Would it be possible to extract only the data in between ( and ) while discarding the other data?
We can use cursors too.
You can use Recursive CTE. I can't think of any better way.
;WITH cte
AS (SELECT *,
Row_number()OVER(ORDER BY start) rn
FROM Yourtable),
rec_cte
AS (SELECT *,
( [End] - Start ) AS st,
1 AS grp
FROM cte
WHERE rn = 1
UNION ALL
SELECT a.*,
CASE
WHEN st + ( a.[End] - a.Start ) >= 500 THEN a.[End] - a.Start
ELSE st + ( a.[End] - a.Start )
END,
CASE
WHEN st + ( a.[End] - a.Start ) >= 500 THEN b.grp + 1
ELSE grp
END
FROM cte a
JOIN rec_cte b
ON a.rn = b.rn + 1)
SELECT Min(Start) as Start,
Max([End]) as [End],
Max(st) as Quantity
FROM rec_cte
GROUP BY grp
OPTION (maxrecursion 0)
Here is a proposed solution in MySQL. A similar strategy should work in SQL Server.
drop table if exists TestData;
create table TestData(Start int, End int, Quantity int);
insert TestData values (425,449,24);
insert TestData values (450,474,24);
insert TestData values (475,499,24);
insert TestData values (500,524,24);
insert TestData values (2300,2324,24);
insert TestData values (2400,2499,99);
insert TestData values (2500,2599,99);
insert TestData values (2800,2899,99);
insert TestData values (2900,2999,99);
insert TestData values (3200,3249,49);
insert TestData values (3250,3299,49);
insert TestData values (3300,3349,49);
insert TestData values (3350,3399,49);
insert TestData values (3400,3449,49);
insert TestData values (3500,3549,49);
insert TestData values (3600,3624,24);
insert TestData values (3650,3674,24);
insert TestData values (3700,3724,24);
insert TestData values (3950,3964,14);
insert TestData values (4000,4000,0);
insert TestData values (4150,4399,249);
insert TestData values (4400,4499,99);
insert TestData values (5034,5075,41);
drop table if exists DataRange;
create table DataRange (StartRange int, EndRange int);
insert DataRange values (425, 2599);
insert DataRange values (2800,3549);
insert DataRange values (3600,5075);
select
DataRange.StartRange,DataRange.EndRange
,sum(TestData.quantity) as Quantity
from TestData
inner join DataRange on
(TestData.start between DataRange.StartRange and DataRange.EndRange )
or
(TestData.End between DataRange.StartRange and DataRange.EndRange )
group by DataRange.StartRange,DataRange.EndRange
I previously found the solution to my problem but unfortunately I lost files on my harddrive and I can't find the statement I managed to produce.
I have 2 tables T2REQ and T2STOCK, both have 2 columns (typeID and quantity) and my problem reside in the fact that I can have multiple occurences of SAME typeID in BOTH tables.
What I'm trying to do is SUM(QUANTITY) grouped by typeID and substract the values of T2STOCK from T2REQ but since I have multiple occurences of same typeID in both tables, the SUM I get is multiplied by the number of occurences of typeID.
Here's a sample of T2REQ (take typeID 11399 for example):
typeID quantity
---------- ----------
34 102900
35 10500
36 3220
37 840
11399 700
563 140
9848 140
11486 28
11688 700
11399 390
4393 130
9840 390
9842 390
11399 390
11483 19.5
11541 780
And this is a sample of T2STOCK table :
typeID quantity
---------- ----------
9842 1921
9848 2400
11399 1700
11475 165
11476 27
11478 28
11481 34
11483 122
11476 2
And this is where I'm at for now, I know that the SUM(t2stock.quantity) is affected (multiplied) because of the JOIN 1 = 1 but whatever I tried, I'm not doing it in the right order:
SELECT
t2req.typeID, sum(t2req.quantity), sum(t2stock.quantity),
sum(t2req.quantity) - sum(t2stock.quantity) as diff
FROM t2req JOIN t2stock ON t2req.typeID = t2stock.typeID
GROUP BY t2req.typeID
ORDER BY diff DESC;
typeID sum(t2req.quantity) sum(t2stock.quantity) diff
---------- ------------------- --------------------- ----------
563 140 30 110
11541 780 780 0
11486 28 40 -12
11483 19.5 122 -102.5
9840 390 1000 -610
40 260 940 -680
9842 390 1921 -1531
9848 140 2400 -2260
11399 1480 5100 -3620
39 650 7650 -7000
37 1230 116336 -115106
36 28570 967098 -938528
35 33770 2477820 -2444050
34 102900 2798355 -2695455
You can see that SUM(t2req) for typeID 11399 is correct : 1480
And you can see that the SUM(t2stock) for typeID 11399 is not correct : 5100 instead of 1700 (which is 5100 divided by 3, the number of occurences in t2req)
What would be the best way to avoid multiplications because of multiple typeIDs (in both tables) with the JOIN for my sum substract ?
Sorry for the wall of text, just trying to explain as best as I can since english is not my mother tongue.
Thanks a lot for your help.
You can aggregate before join:
SELECT
t2req.typeID,
t2req.quantity,
t2stock.quantity,
t2req.quantity - t2stock.quantity as diff
FROM
(SELECT TypeID, SUM(Quantity) Quantity FROM t2req GROUP BY TypeID) t2req JOIN
(SELECT TypeID, SUM(Quantity) Quantity FROM t2stock GROUP BY TypeID) t2stock
ON t2req.typeID = t2stock.typeID
ORDER BY diff DESC;
Fiddle sample: http://sqlfiddle.com/#!7/06711/5
You can't do this in a single aggregation:
SELECT
COALESCE(r.typeID, s.typeID) AS typeID,
COALESCE(r.quantity, 0) AS req_quantity,
COALESCE(s.quantity, 0) AS stock_quantity,
COALESCE(r.quantity, 0) - COALESCE(s.quantity, 0) AS diff
FROM (
SELECT rr.typeID, SUM(rr.quantity) AS quantity
FROM t2req rr
GROUP BY rr.typeID
) r
CROSS JOIN (
SELECT ss.typeID, SUM(ss.quantity) AS quantity
FROM t2stock ss
GROUP BY ss.typeID
) s ON r.typeID = s.typeID
ORDER BY 4 DESC;
I have four tables in the database as follows:
tblInvoice:
invcid,customerid,invoicedate
tblInvcDetail:
ID,invcid,item,itemprice,itemquantity
tblPay:
payid,invcid,paydate
tblPayDetail:
payid,amount
I need to create a list of invoiceid, invoicedate, (sum of itemprice*itemquantity), (sum of amount) where userid is given.
I tried this query:
SELECT tblinvoice.invcid,
tblinvoice.invcdate,
Sum(tblinvcdetail.itemprice * tblinvcdetail.itemquantity) AS SumOfInvoice,
Sum(tblpaydetail.amount) AS SumOfAmount
FROM ((tblinvoice
LEFT JOIN tblpay
ON tblinvoice.invcid = tblpay.invcid)
LEFT JOIN tblinvcdetail
ON tblinvoice.invcid = tblinvcdetail.invcid)
LEFT JOIN tblpaydetail
ON tblpay.payid = tblpaydetail.payid
GROUP BY tblinvoice.invcid,
tblinvoice.invcdate;
But the result is not quite correct
Please help me.
Thanks a lot.
Sample data:
tblInvoice:
invcid customerid invcdate |invcsum(manualy calculated)
18 8 6/30/2012 |$140,000
39 8 7/12/2012 |$170,000
40 8 7/12/2012 |$80,000
43 8 7/14/2012 |$80,000
44 8 7/14/2012 |$80,000
45 8 7/15/2012 |$700,000
46 8 7/17/2012 |$180,000
tblInvcDetail:
ID invccid itemname itemprice itemquantity
19 18 X $70,000 2
92 39 Y $80,000 1
93 39 Z $90,000 1
94 40 Y $80,000 1
97 43 Y $80,000 1
98 44 Y $80,000 1
99 45 W $700,000 1
100 46 Y $80,000 1
101 46 U $100,000 1
tblPay:
payid invcid paydate |AmountSUM(Manually Calculated)
35 18 7/11/2012 |$120,000
40 18 7/12/2012 |$147,000
41 40 7/12/2012 |$84,000
44 44 7/14/2012 |$84,000
46 45 7/15/2012 |$700,000
tblPayDetail:
payid amount
35 $100,000
35 $20,000
40 $147,000
41 $84,000
44 $84,000
46 $700,000
And finally the query result is:
invcid invcdate SumOfInvoice SumOfAmount
18 6/30/2012 $420,000.00 $267,000.00
39 7/12/2012 $170,000.00
40 7/12/2012 $80,000.00 $84,000.00
43 7/14/2012 $80,000.00
44 7/14/2012 $80,000.00 $84,000.00
45 7/15/2012 $700,000.00 $700,000.00
46 7/17/2012 $180,000.00
You can see that the calculation is wrong in the first row (SumOfInvoice column)
and the rest is correct!
How about:
SELECT a.invcid,
a.invcdate,
a.sumofinvoice,
b.sumofamount
FROM (SELECT ti.invcid,
ti.invcdate,
SUM(td.itemprice * td.itemquantity) AS SumOfInvoice
FROM tblinvoice AS ti
LEFT JOIN tblinvcdetail AS td
ON ti.invcid = td.invcid
GROUP BY ti.invcid,
ti.invcdate) a
LEFT JOIN (SELECT tp.invcid,
SUM(tpd.amount) AS SumOfAmount
FROM tblpay AS tp
LEFT JOIN tblpaydetail AS tpd
ON tp.payid = tpd.payid
GROUP BY tp.invcid) b
ON a.invcid = b.invcid