Pivot Nested Columns (Grouped by Columns) - SQL Server - sql

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.

Related

count number of records by month over the last five years where record date > select month

I need to show the number of valid inspectors we have by month over the last five years. Inspectors are considered valid when the expiration date on their certification has not yet passed, recorded as the month end date. The below SQL code is text of the query to count valid inspectors for January 2017:
SELECT Count(*) AS RecordCount
FROM dbo_Insp_Type
WHERE (dbo_Insp_Type.CERT_EXP_DTE)>=#2/1/2017#);
Rather than designing 60 queries, one for each month, and compiling the results in a final table (or, err, query) are there other methods I can use that call for less manual input?
From this sample:
Id
CERT_EXP_DTE
1
2022-01-15
2
2022-01-23
3
2022-02-01
4
2022-02-03
5
2022-05-01
6
2022-06-06
7
2022-06-07
8
2022-07-21
9
2022-02-20
10
2021-11-05
11
2021-12-01
12
2021-12-24
this single query:
SELECT
Format([CERT_EXP_DTE],"yyyy/mm") AS YearMonth,
Count(*) AS AllInspectors,
Sum(Abs([CERT_EXP_DTE] >= DateSerial(Year([CERT_EXP_DTE]), Month([CERT_EXP_DTE]), 2))) AS ValidInspectors
FROM
dbo_Insp_Type
GROUP BY
Format([CERT_EXP_DTE],"yyyy/mm");
will return:
YearMonth
AllInspectors
ValidInspectors
2021-11
1
1
2021-12
2
1
2022-01
2
2
2022-02
3
2
2022-05
1
0
2022-06
2
2
2022-07
1
1
ID
Cert_Iss_Dte
Cert_Exp_Dte
1
1/15/2020
1/15/2022
2
1/23/2020
1/23/2022
3
2/1/2020
2/1/2022
4
2/3/2020
2/3/2022
5
5/1/2020
5/1/2022
6
6/6/2020
6/6/2022
7
6/7/2020
6/7/2022
8
7/21/2020
7/21/2022
9
2/20/2020
2/20/2022
10
11/5/2021
11/5/2023
11
12/1/2021
12/1/2023
12
12/24/2021
12/24/2023
A UNION query could calculate a record for each of 50 months but since you want 60, UNION is out.
Or a query with 60 calculated fields using IIf() and Count() referencing a textbox on form for start date:
SELECT Count(IIf(CERT_EXP_DTE>=Forms!formname!tbxDate,1,Null)) AS Dt1,
Count(IIf(CERT_EXP_DTE>=DateAdd("m",1,Forms!formname!tbxDate),1,Null) AS Dt2,
...
FROM dbo_Insp_Type
Using the above data, following is output for Feb and Mar 2022. I did a test with Cert_Iss_Dte included in criteria and it did not make a difference for this sample data.
Dt1
Dt2
10
8
Or a report with 60 textboxes and each calls a DCount() expression with criteria same as used in query.
Or a VBA procedure that writes data to a 'temp' table.

(SQL)How to Get absence "day" from date under 1-31 column using PIVOT

I have a table abs_details that give data like follows -
PERSON_NUMBER ABS_DATE ABS_TYPE_NAME ABS_DAYS
1010 01-01-2022 PTO 1
1010 06-01-2022 PTO 0.52
1010 02-02-2022 VACATION 1
1010 03-02-2022 VACATION 0.2
1010 01-12-2021 PTO 1
1010 02-12-2021 sick 1
1010 30-12-2021 sick 1
1010 30-01-2022 SICK 1
I want this data to be displayed in the following way:
PERSON_NUMBER ABS_TYPE_NAME 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
1010 PTO 2 0.52
1010 VACATION 1 0.2
1010 SICK 1 2
For the days, 1-31 should should come in the header, if there is any absence taken on say 01st of the month or quarter passed then the value should go under 1 , if there is no value for date of the month, say no value is there from 07th-11th in the above case, then output should display the numbers but no value should be provided under it.
Is this feasible in SQL? I have an idea we can use pivot, but how to fix 1-31 header and give values underneath each day.
Any suggestions?
If I pass multiple quarter that is Q1(JAN-MAR), Q2(APR-JUN) it should sum up the values between the dates between those two quarters. if Just q1 then only q1 result
If I pass multiple month then it should display the sum of the values for an absence type in those multiple months.
I will be passing the year in the parameter and the above two should consider the year I pass.
Create a column which has all the dates, and pivot up using pivot function in oracle.
SELECT *
FROM
(
SELECT PERSON_NUMBER,
EXTRACT(DAY FROM TO_DATE(ABS_DATE)) AS DAY_X,
ABS_TYPE_NAME,
ABS_DAYS
FROM TABLE
-- Add additional filter here which you want
)
PIVOT(SUM(ABS_DAYS)
FOR DAY_X IN (0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31))
Db fiddle - https://dbfiddle.uk/?rdbms=oracle_21&fiddle=ad3af639235f7a6db415ec714a3ee0d9

Max date among records and across tables - SQL Server

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 );

SQL - Column per week (X weeks from declared start date) [duplicate]

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

How to query to get totals for last seven days?

I am using SQL Server 2008.
I want to write a query that gives me total activity for a number of given days. Specifically, I want to count total votes per day for the last seven days.
My table looks like this:
VoteID --- VoteDate -------------- Vote --- BikeID
1 2012-01-01 08:24:25 1 1234
2 2012-01-01 08:24:25 0 5678
3 2012-01-02 08:24:25 1 1289
4 2012-01-03 08:24:25 0 1234
5 2012-01-04 08:24:25 1 5645
6 2012-01-05 08:24:25 0 1213
7 2012-01-06 08:24:25 1 1234
8 2012-01-07 08:24:25 0 1125
I need my results to look like this
VoteDate ---- Total
2012-01-01 5
2012-01-02 6
2012-01-03 7
2012-01-04 1
2012-01-05 3
My thought is that I have to do something like this:
SELECT SUM(CASE WHEN Vote = 1 THEN 1 ELSE 0 END) AS Total
FROM Votes
GROUP BY VoteDate
This query doesn't work because it counts only votes that occurred (almost exactly) at the same time. Of course, I want to look only at a specific day. How do I make this happen?
Cast it as a date:
SELECT
cast(VoteDate as date) as VoteDate,
SUM(CASE WHEN Vote = 1 THEN 1 ELSE 0 END) AS Total
FROM Votes
WHERE VoteDate between dateadd(day, -7, GETDATE()) and GETDATE()
GROUP BY cast(VoteDate as date)
Your VoteDate column is a datetime, but you just want the date part of it. The easiest way to do that is to cast it as a date type. You can read more about SQL Server date types here.
And if your Vote column is either 1 or 0, you can just do sum(vote) as Total instead of doing the case statement.
SELECT SUM(Vote) As Total, YEAR(VoteDate),Month(VoteDate),Day(VoteDate)
FROM Votes
Group By YEAR(VoteDate),Month(VoteDate),Day(VoteDate)
Some SQL Server functions that may be of interest
Some MySQL functions that may be of interest