This question already has an answer here:
SQL Server: Dynamic pivot with headers to include column name and date
(1 answer)
Closed 8 years ago.
I need to run a select statement that returns a number of invoices with their values showing in a column that's appropriate to the week that the invoice appeared in. Example:
id value invoiced
1 150 2014-01-06
2 220 2014-01-13
3 190 2014-01-13
4 880 2014-01-27
5 325 2014-02-03
I would need this data to display in a format similar to below:
ID W/E 2014-01-05 W/E 2014-01-12 W/E 2014-01-19 W/E 2014-01-26 W/E 2014-02-02 W/E 2014-02-09 W/E 2014-02-16
1 0 150 0 0 0 0 0
2 0 0 220 0 0 0 0
3 0 0 190 0 0 0 0
4 0 0 0 0 880 0 0
5 0 0 0 0 0 325 0
With the first date being taken from a variable and the remaining weeks being calculated from that point on (for X weeks). My initial thought is to use a temporary table to hold rows for each of the date ranges and then join that table to perform a pivot... but to be honest this is all pretty new to me so I have absolutely no idea of the syntax.
There is no requirement for any grouping (no sums to deal with), I just need to make sure that the appropriate values end up in the appropriate columns.
p.s. I know I could do this with loops on the presentation layer, but in this particular case, there isn't one as such.
declare #t table (Id INT,Value INT,invoiced Date )
insert into #t (Id,Value,invoiced)values (1,150,'2014-01-06')
insert into #t (Id,Value,invoiced)values (2,220,'2014-01-13')
insert into #t (Id,Value,invoiced)values (3,190,'2014-01-15')
insert into #t (Id,Value,invoiced)values (4,880,'2014-01-27')
insert into #t (Id,Value,invoiced)values (5,325,'2014-01-29')
Select id,
[w/e2014-01-06],
[w/e2014-01-13],
[w/e2014-01-15],
[w/e2014-01-27],
[w/e2014-01-29]
from
(Select distinct t.ID,t.Value,
'w/e' + CAST(t.invoiced AS VARCHAR)AS Dateno
from #t t)t
PIVOT (MAX(value)FOR Dateno IN([w/e2014-01-06],[w/e2014-01-13],[w/e2014-01-15],[w/e2014-01-27],[w/e2014-01-29]))p
Related
I have the receiving and sending data for whole year. so i want to built the monthly report base on that data with the rule is Fisrt in first out. It means is the first receiving will be sent out first ...
DECLARE #ReceivingTbl AS TABLE(Id INT,ProId int, RecQty INT,ReceivingDate DateTime)
INSERT INTO #ReceivingTbl
VALUES (1,1001,210,'2019-03-12'),
(2,1001,315,'2019-06-15'),
(3,2001,500,'2019-04-01'),
(4,2001,10,'2019-06-15'),
(5,1001,105,'2019-07-10')
DECLARE #SendTbl AS TABLE(Id INT,ProId int, SentQty INT,SendMonth int)
INSERT INTO #SendTbl
VALUES (1,1001,50,3),
(2,1001,100,4),
(3,1001,80,5),
(4,1001,80,6),
(5,2001,200,6)
SELECT * FROM #ReceivingTbl ORDER BY ProId,ReceivingDate
SELECT * FROM #SendTbl ORDER BY ProId,SendMonth
Id ProId RecQty ReceivingDate
1 1001 210 2019-03-12
2 1001 315 2019-06-15
5 1001 105 2019-07-10
3 2001 500 2019-04-01
4 2001 10 2019-06-15
Id ProId SentQty SendMonth
1 1001 50 3
2 1001 100 4
3 1001 80 5
4 1001 80 6
5 2001 200 6
--- And the below is what i want:
Id ProId RecQty ReceivingDate ... Mar Apr May Jun
1 1001 210 2019-03-12 ... 50 100 60 0
2 1001 315 2019-06-15 ... 0 0 20 80
5 1001 105 2019-07-10 ... 0 0 0 0
3 2001 500 2019-04-01 ... 0 0 0 200
4 2001 10 2019-06-15 ... 0 0 0 0
Thanks!
Your question is not clear to me.
If you want to purely use the FIFO approach, therefore ignore any data the table contains, you necessarely need to order by ID, which in your example you are providing, and looks like it is in order of insert.
The first line inserted should be also the first line appearing in the select (FIFO), in order to do so you have to use:
ORDER BY Id ASC
Which will place the lower value of the ID first (1, 2, 3, ...)
To me though, this doesn't make much sense, so pay attention to the meaning o the data you actually have and leverage dates like ReceivingDate, and order by that, maybe even filtering by month of the date, below an example for January data:
WHERE MONTH(ReceivingDate) = 1
I'm trying to figure out if I can pivot these results as desired or if I need to code this report in Crystal or something.
DATA TO CREATE TABLE:
CREATE TABLE
#TempData (
EMP NVARCHAR(35),
WKDAY NVARCHAR(3),
ENTRY_DATE DATETIME,
REG_HOURS INT,
OT_HOURS INT,
PTO_HOURS INT);
INSERT INTO #TempData (EMP, WKDAY, ENTRY_DATE, REG_HOURS, OT_HOURS, PTO_HOURS)
VALUES ('Doe, John','Fri','2018-03-16 00:00:00.000','10','2','35'),
('Boop, Betty','Fri','2018-03-16 00:00:00.000','8','3','48'),
('Boop, Betty','Mon','2018-03-19 00:00:00.000','8','8','63'),
('Square, Sponge','Mon','2018-03-19 00:00:00.000','9','7','21'),
('Rabbit, Roger','Tue','2018-03-20 00:00:00.000','5','9','45'),
('Square, Sponge','Tue','2018-03-20 00:00:00.000','9','0','9'),
('Boop, Betty','Wed','2018-03-21 00:00:00.000','0','4','18'),
('Doe, John','Wed','2018-03-21 00:00:00.000','12','4','57'),
('Matrix, Neo','Thu','2018-03-22 00:00:00.000','8','6','24');
The results desired would be as seen in the below Pivot Nested Columns (Grouped by Columns):
WKDAY DATE Doe, John Boop, Betty Square, Sponge Rabbit, Roger
REG_HOURS OT_HOURS PTO_HOURS REG_HOURS OT_HOURS PTO_HOURS REG_HOURS OT_HOURS PTO_HOURS REG_HOURS OT_HOURS PTO_HOURS
Fri 2018-03-16 00:00:00.000 10 2 35 8 3 48 0 0 0 0 0 0
Mon 2018-03-19 00:00:00.000 0 0 0 8 8 63 9 7 21 0 0 0
Tue 2018-03-20 00:00:00.000 0 0 0 0 0 0 9 0 9 5 9 45
It should be in this exact format, I don't want to consolidate column names via date or any other combination.
Is this possible?
The only alternative I see is coding it in a report like Crystal Reports or something like that.
Pivot in the presentation layer. Crystal Reports, Excel, Access, Tableau, whatever.
In SQL Server, there is no concept of Column Groups.
You could get a result like this:
WKDAY DATE Doe_John_REG_HOURS Doe_John_OT_HOURS Doe_John_PTO_HOURS Boop_Betty_REG_HOURS Boop_Betty_OT_HOURS Boop_Betty_PTO_HOURS etc...
But the only way to have the exact format in your question, with two rows of column headers, is in a presentation layer.
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!
I tried max to provide in table format but it seem not good in StackOver, so attaching snapshot of the 2 tables. Apologize about the formatting.
SQL Server 2012
**MS Table**
**mId tdId name dueDate**
1 1 **forecastedDate** 1/1/2015
2 1 **hypercareDate** 11/30/2016
3 1 LOE 1 7/4/2016
4 1 LOE 2 7/4/2016
5 1 demo for yy test 10/15/2016
6 1 Implementation – testing 7/4/2016
7 1 Phased Rollout – final 7/4/2016
8 2 forecastedDate 1/7/2016
9 2 hypercareDate 11/12/2016
10 2 domain - Forte NULL
11 2 Fortis completion 1/1/2016
12 2 Certification NULL
13 2 Implementation 7/4/2016
-----------------------------------------------
**MSRevised**
**mId revisedDate**
1 1/5/2015
1 1/8/2015
3 3/25/2017
2 2/1/2016
2 12/30/2016
3 4/28/2016
4 4/28/2016
5 10/1/2016
6 7/28/2016
7 7/28/2016
8 4/28/2016
9 8/4/2016
9 5/28/2016
11 10/4/2016
11 10/5/2016
13 11/1/2016
----------------------------------------
The required output is
1. Will be passing the 'tId' number, for instance 1, lets call it tid (1)
2. Want to compare tId (1)'s all milestones (except hypercareDate) with tid(1)'s forecastedDate milestone
3. return if any of the milestone date (other than hypercareDate) is greater than the forecastedDate
The above 3 steps are simple, but I have to first compare the milestones date with its corresponding revised dates, if any, from the revised table, and pick the max date among all that needs to be compared with the forecastedDate
I managed to solve this. Posting the answer, hope it helps aomebody.
//Insert the result into temp table
INSERT INTO #mstab
SELECT [mId]
, [tId]
, [msDate]
FROM [dbo].[MS]
WHERE ([msName] NOT LIKE 'forecastedDate' AND [msName] NOT LIKE 'hypercareDate'))
// this scalar function will get max date between forecasted duedate and forecasted revised date
SELECT #maxForecastedDate = [dbo].[fnGetMaxDate] ( 'forecastedDate');
// this will get the max date from temp table and compare it with forecasatedDate/
SET #maxmilestoneDate = (SELECT MAX(maxDate)
FROM ( SELECT ms.msDueDate AS dueDate
, mr.msRevisedDate AS revDate
FROM #mstab as ms
LEFT JOIN [MSRev] as mr on ms.msId = mr.msId
) maxDate
UNPIVOT (maxDate FOR DateCols IN (dueDate, revDate))up );
I have a data.frame like below.
toolid startdate enddate stage
abc 1-Jan-13 5-Jan-13 production
abc 6-Jan-13 10-Jan-13 down
xyz 3-Jan-13 8-Jan-13 production
xyz 9-Jan-13 15-Jan-13 down
I want to get final output which will be like below. The output needs to return - count of each stage (there could be more than 2 stages) over each day between 1jan13 to 15jan13 (or any date range that an user wants). I was able to create the required result in R. I also wrote a cursor in SQL and it achieves the purpose. But is there a way to do the same without using cursors? I am looking for logic and direction.
date down production
1 2013-01-01 0 1
2 2013-01-02 0 1
3 2013-01-03 0 2
4 2013-01-04 0 2
5 2013-01-05 0 2
6 2013-01-06 1 1
7 2013-01-07 1 1
8 2013-01-08 1 1
9 2013-01-09 2 0
10 2013-01-10 2 0
11 2013-01-11 1 0
12 2013-01-12 1 0
13 2013-01-13 1 0
14 2013-01-14 1 0
15 2013-01-15 1 0
I think this may be what you want. It requires a recursive CTE to get a row for each day in the range.
with daterange as (
select startdate=min(startdate),enddate=max(enddate) from #source
), dates as (
select d=(select startdate from daterange) union all
select dateadd(day,1,d) from dates where d<(select enddate from daterange)
)
select
d,
down=(select count(*) from #source where d between startdate and enddate and stage='down'),
production=(select count(*) from #source where d between startdate and enddate and stage='production')
from dates
order by d;