This is a two part question. I have a base table that looks like this:
DATE ID START_DATE QTY ROW
2011-01-31 1 2009-04-30 40 1
2011-01-31 1 2009-10-31 5 2
2011-01-31 1 2010-01-15 10 3
2011-01-31 2 2009-09-15 50 1
2011-01-31 3 2010-05-25 20 1
2011-01-31 3 2010-06-01 10 2
2011-01-31 3 2010-09-01 200 3
I want to expand out rows into columns, adding two columns for each row (QTY and START_DATE) so that each date + ID has only one line:
DATE ID SD1 QTY1 SD2 QTY2 SD3 QTY3
2011-01-31 1 2009-04-30 40 2009-10-31 5 2010-01-15 10
2011-01-31 2 2009-09-15 50 NULL NULL NULL NULL
2011-01-31 3 2010-05-25 20 2010-06-01 10 2010-09-01 200
Right now I have up to 44 that I need to add (MAX(ROW)), but in the future there could be more. I can manually add the 44 by doing:
max(CASE WHEN ROW = 1 THEN q.START_DATE END) AS SD1,
SUM(CASE WHEN ROW = 1 THEN q.QTY END) AS QTY1,
max(CASE WHEN ROW = 2 THEN q.START_DATE END) AS SD2,
SUM(CASE WHEN ROW = 2 THEN q.QTY END) AS QTY2,
...
max(CASE WHEN ROW = n THEN q.START_DATE END) AS SDn,
SUM(CASE WHEN ROW = n THEN q.QTY END) AS QTYn
My first question, if I fix the number at say 50, is there a clean way for me to add those 100 columns in my code, or do I just need to explicitly show all 100 lines?
Second question, is there a way for me to use MAX(ROW) to tell the statement how many columns to add? Meaning if MAX(ROW) = 10, add SD1 - SD10 and QTY1 - QTY10. But if on next run MAX(ROW) = 100, add SD1 - SD100, QTY1 - QTY100
Thanks!
Related
I'm using SQL Server 2016.
I have the below table:
SKU Shop Week ShopPrioirty Replen Open_Stk Open_Stk Calc
111 100 1 1 0 17 NULL
111 200 1 2 2 NULL NULL
111 300 1 3 0 NULL NULL
111 400 1 4 0 NULL NULL
222 100 2 1 5 17 NULL
222 200 2 2 5 NULL NULL
222 300 2 3 5 NULL NULL
222 400 2 4 5 NULL NULL
This is the desired result:
SKU Shop Week ShopPrioirty Replen Open_Stk Open_Stk Calc
111 100 1 1 0 17 17
111 200 1 2 2 NULL 17
111 300 1 3 0 NULL 15
111 400 1 4 0 NULL 15
222 100 2 1 20 17 17
222 200 2 2 15 NULL 12
222 300 2 3 12 NULL 7
222 400 2 4 10 NULL 2
I need to update the 'Open_Stk Calc' based on the previous row:
'Open_Stk Calc' - IIF('Replen'<=IIF('Open_Stk'>=0,'Open_Stk',0),'Replen',0)
I am using a CTE to update a row based on a calculation of the previous rows. This is my SQL:
;WITH CTE AS
(
SELECT
SKU,
[Shop],
[Week],
[Store_Priority],
[Replen],
[Open_Stk],
[Open_Stk Calc],
FIRST_VALUE([Open_Stk]) OVER ( PARTITION BY [SKU] ,[Week] ORDER BY [Store_Priority] ROWS UNBOUNDED PRECEDING)
-
ISNULL(SUM(IIF([Replen] <= IIF([Open_Stk]>=0,[Open_Stk],0),[Replen],0))
OVER (PARTITION BY [SKU] ,[Week] ORDER BY [Store_Priority] ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) AS CurrentStock
FROM [tblTEST])
UPDATE CTE
SET [Open_Stk Calc] = CurrentStock
However, this produces the following result:
SKU Shop Week ShopPrioirty Replen Open_Stk Open_Stk Calc
111 100 1 1 0 17 17
111 200 1 2 2 NULL 17
111 300 1 3 0 NULL 17
111 400 1 4 0 NULL 17
And not the desired result - where have I gone wrong?
As one can see in the MS documentation, the OVER clauses supports specific kind of functions:
Ranking functions
Aggregate functions
Analytic functions
NEXT VALUE FOR function
None of them include IIF, as Luis Cazares noted in their comment.
Your code indicates you do have a clue about what you are doing - maybe you forgot to put your IIF inside a SUM?
I have this table (I put the name over needed colums)
iddip date idv idc val
47 2018-06-01 00:00:00.000 0 3 3 60 NULL NULL
47 2018-06-01 00:00:00.000 0 1 3 200 NULL NULL
47 2018-06-01 00:00:00.000 0 1 4 280 NULL NULL
43 2018-06-01 00:00:00.000 0 3 2 510 NULL NULL
53 2018-06-01 00:00:00.000 0 1 4 480 NULL NULL
29 2018-06-01 00:00:00.000 0 3 2 510 NULL NULL
2 2018-06-11 00:00:00.000 0 1 2 480 NULL NULL
47 2018-06-02 00:00:00.000 0 1 3 100 NULL NULL
I want to obtain this:
id idc Totidv1 Totidv3 TOT
47 3 300 60 360
47 4 280 0 280
43 2 0 510 510
53 4 480 0 480
29 2 0 510 510
2 2 480 0 480
The closest I can get is:
SELECT DISTINCT(iddip),IDCENTROCOSTO,tot=SUM(VALORE),ord=( SELECT SUM(isnull(VALORE,0)) FROM VALORIVOCICDC WHERE IDVOCE='1' and iddip=v.IDDIP and IDCENTROCOSTO ='3' GROUP BY iddip,IDCENTROCOSTO),
str=( SELECT SUM(isnull(VALORE,0)) FROM VALORIVOCICDC WHERE IDVOCE='3' and iddip=v.IDDIP and IDCENTROCOSTO ='3' GROUP BY iddip,IDCENTROCOSTO)
FROM VALORIVOCICDC v
GROUP BY v.iddip,IDCENTROCOSTO
But it returns wrong sums in totidv1 and totisv3, How can I do this? Thanks for any hint
You just need a GROUP BY here (not distinct) and a couple of CASE statements:
SELECT
id,
idc,
SUM(CASE WHEN idv=3 THEN idv ELSE 0 END) as totidv1,
SUM(CASE WHEN idv=1 THEN idv ELSE 0 END) as totidv3,
SUM(idv) as Tot
FROM yourtable
GROUP BY id, idc
Note that Distinct is not a function that you can call like SELECT DISTINCT(somecolumn) This is functionally equivalent to SELECT DISTINCT somecolumn... in that it works against the entire record set returned by the SELECT statement either way.
I'm just starting to get a hang of SQL but I've tried to find an answer to this but with no avail.
I have a table that kinda looks like this:
date base version prod_id place
2016-01-02 1 1 22 home
2016-01-02 1 1 22 home
2016-01-02 1 1 1 home
2016-01-02 1 1 1 store
2016-01-02 1 1 22 store
2016-01-02 1 1 2 store
2016-01-02 1 1 2 web
2016-01-02 1 1 24 web
2016-01-02 1 1 1 web
2016-01-02 1 2 24 home
2016-01-02 1 2 22 home
2016-01-02 1 2 22 store
2016-01-02 1 2 1 store
2016-01-02 1 2 2 web
2016-01-03 1 1 22 home
2016-01-03 1 1 22 home
2016-01-03 1 1 1 home
2016-01-03 1 1 24 store
2016-01-03 1 2 24 store
2016-01-03 1 2 22 web
2016-01-03 1 2 1 web
2016-01-03 1 2 2 web
2016-01-03 1 2 1 web
I'm trying to do a query that gives me this
date base version place 1,2 22,24 Total
2016-01-02 1 1 home 1 2 3
2016-01-02 1 1 store 2 1 3
2016-01-02 1 1 web 2 1 3
2016-01-02 1 2 home 2 0 2
2016-01-02 1 2 store 1 1 2
2016-01-02 1 2 web 1 0 1
2016-01-03 1 1 home 2 1 3
2016-01-03 1 1 store 0 1 1
2016-01-03 1 2 store 0 1 1
2016-01-03 1 2 web 3 0 3
So to put it in words: I'm trying to group and count the occurances of each value in prod_id and put them in an column. And its not only one value that needs to be counted and grouped together, sometimes two or more. So in this example i've added up all occurances of 1 and 2 on a specific date, version and place and so also 22 and 24. Do I make any sense?
Nice problem. You can count a complicated CASE.
The query
SELECT
prod_id,
CASE WHEN prod_id IN (1,2) THEN 1 ELSE 0 AS v1Or2,
CASE WHEN prod_id IN (22,24) THEN 1 ELSE 0 AS v22or24
FROM table1
This gives you something you can usefully SUM
prod_id v1or2 v22or24
22 0 1
22 0 1
1 1 0
1 1 0
22 0 1
2 1 0
2 1 0
With the appropriate GROUP BY you have...
SELECT date,place,base,version,
SUM(CASE WHEN prod_id IN (1,2) THEN 1 ELSE 0) AS v1Or2,
SUM(CASE WHEN prod_id IN (22,24) THEN 1 ELSE 0) AS v22or24
FROM table1
GROUP BY date,place,base,version
Select [Date]
,Base
,[version]
,place
,SUM(Case when prod_id IN (1,2) THEN 1 ELSE 0 END) AS [1,2]
,SUM(Case when prod_id IN (22,24) THEN 1 ELSE 0 END) AS [22,24]
,Count(*) AS Total
From TableName
GROUP BY [Date] ,Base ,[version],place
You can solve this by combining the sum aggregate function with case expressions to do the counts based on what value the prod_id has. This technique is sometimes referred to as conditional aggregation.
Try this:
select
date, base, version, place,
sum(case when prod_id in (1,2) then 1 else 0 end) as "1,2",
sum(case when prod_id in (22,24) then 1 else 0 end) as "22,24",
count(prod_id) as Total
from your_table
group by date, base, version, place
order by date, base, version;
I would like to get report for drink purchased in whole month but price of the drink can change any time in month and I would like to get report for a month with price change
I have two tables
SELECT [ID]
,[DrinkID]
,[UserID]
,[qty]
,[DateTaken]
FROM [Snacks].[dbo].[DrinkHistory]
SELECT [ID]
,[DrinkID]
,[UserID]
,[qty]
,[DateTaken]
FROM [Snacks].[dbo].[DrinkHistory]
[DrinkHistory]:
ID DrinkID UserID qty DateTaken
----------------------------------------------------------------------
1 1 1 1 2014-05-10
2 1 1 2 2014-05-15
3 2 1 1 2014-06-01
4 2 1 4 2014-06-01
5 1 1 3 2014-05-20
6 1 1 4 2014-05-30
[DrinkPricesEffect]:
PriceID DrinkID DrinkPrice PriceEffectiveDate IsCurrent
-----------------------------------------------------------------------------------
1 1 10.00 2014-05-01 1
2 1 20.00 2014-05-20 1
3 2 9.00 2014-06-01 1
4 2 8.00 2014-01-01 1
5 1 30.00 2014-05-25 1
6 1 40.00 2014-05-28 1
I would like to have result as under date taken between 2014-05-1 to 2014-05-31
DrinkId Qty Price DateTaken PriceEffectiveDate
-----------------------------------------------------------------------
1 1 10 2014-05-10 2014-05-01
1 2 10 2014-05-15 2014-05-01
1 3 20 2014-05-20 2014-05-20
1 4 40 2014-05-30 2014-05-28
Is there any who can give me some idea or write query for me?
If your drink price can change any time in a month you could additionaly save the price for each purchase. I would add a column [PricePaid] to the table [DrinkHistory].
When adding a record to [DrinkHistory], the price for the drink at the moment is known, but later it might change so you save the current price to the history...
Then for your result you could just display the Whole [DrinkHistory]
SELECT * FROM DrinkHistory;
This should work:
Select
DH.DrinkId,
DH.Qty,
DPE.DrinkPrice AS Price,
DH.DateTaken,
DPE.PriceEffectiveDate
FROM DrinkHistory DH
JOIN DrinkPricesEffect DPE ON DPE.PriceID =
(
Select Top 1 PriceID FROM
(
Select PriceID,RANK() OVER(ORDER BY PriceEffectiveDate DESC ) AS rnk
FROM DrinkPricesEffect
WHERE DH.DrinkId = DrinkId AND
DH.DateTaken >= PriceEffectiveDate
)SubQ WHERE rnk = 1
)
WHERE DH.DateTaken Between '2014-05-01' AND '2014-05-30'
Here you can find the SQL Fiddle link: http://sqlfiddle.com/#!6/5f8fb/26/0
I have a set of data that looks like below
Name Time Perc Group Mode Control Cancelled
A 10:52 10.10 10 0 1 0
B 09:00 10.23 10 1 1 1
C 12:02 12.01 12 0 1 1
D 10:45 12.12 12 1 7 1
E 12:54 12.56 12 1 3 0
F 01:01 13.90 13 0 11 1
G 02:45 13.23 13 1 12 1
H 09:10 13.21 13 1 1 0
I need an output like below;
Group Perc Cancelled
10 20.33 1
12 36.69 2
13 40.34 2
What I'm getting was something like;
Group Perc Cancelled
10 20.33 5
12 36.69 5
13 40.34 5
I don't know what to call this, I have something in my mind to call it like CTE?, but I really can't figure it out.
Here's my source;
SELECT Group, SUM(Perc), Cancelled FROM
(SELECT Group, Perc, (SELECT COUNT(*) FROM tblName WHERE Cancelled=1) AS Cancelled FROM tblName WHERE 1=1 AND Group>=10)dt
GROUP BY Group, Cancelled
From your example, you don't need the nested query, any recursion, etc...
SELECT
Group,
SUM(Perc) AS total_perc,
SUM(cancelled) AS total_cancelled
FROM
tblName
WHERE
1=1
AND Group >= 10
GROUP BY
Group
If you did have some different data, then you might want to use something like...
SUM(CASE WHEN cancelled > 0 THEN 1 ELSE 0 END) AS total_cancelled