Using Pivoting in SQL Server (Error) - Invalid column name - sql-server

SELECT
[Reg. number], [Surname],
[SESREFDATETIME1], [ATTENDANCE1],
[SESREFDATETIME2], [ATTENDANCE2],
[SESREFDATETIME3], [ATTENDANCE3],
[SESREFDATETIME4], [ATTENDANCE4]
FROM
(SELECT
[Reg. number], [Surname],
col + CAST(rn AS varchar(10)) col,
value
FROM
(SELECT
[Reg. number], Surname,
row_number() over(partition by [Reg. number] order by SESREFDATETIME) rn
FROM #Temp) t
CROSS APPLY
(SELECT 'SESREFDATETIME', SESREFDATETIME
UNION ALL
SELECT 'ATTENDANCE', ATTENDANCE) c (col, value)
) x
PIVOT
(max(value)
for col in ([SESREFDATETIME1], [ATTENDANCE1], [SESREFDATETIME2],[ATTENDANCE2], [SESREFDATETIME3], [ATTENDANCE3], [SESREFDATETIME4],[ATTENDANCE4])
) p;
In my procedure I created a #temp temporary table and I tried to show multiple lines in multiple columns. The reason I used pivot because this code created dynamically and number of rows aren't known. I am running the code but it gives error. I am going to be crazy. Can't find where is the error. It shows that in cross apply there is invalid column name. I think there is another error. And it shows error in wrong side.
For testing table format is as following
Create table #Temp
(
[Reg. number] int,
[Surname] Varchar(50),
SESREFDATETIME Varchar(80),
ATTENDANCE Varchar(10)
)
Example data format is
2005162 Abasov 04/09/2014 09:00 - 10:00 Y
2005458 Baxşiyev 15/04/2015 01:00 - 04:00 NULL
2005458 Baxşiyev 16/09/2014 14:00 - 17:00 Y
2005538 Abbasbəyli 13/10/2014 12:00 - 15:00 Y

Your 'cross apply x' can't see SESREFDATETIME and ATTENDANCE, if you include those columns in your 'subselect t' the cross apply part can get the values
Try this:
SELECT
[Reg. number], [Surname],
[SESREFDATETIME1], [ATTENDANCE1],
[SESREFDATETIME2], [ATTENDANCE2],
[SESREFDATETIME3], [ATTENDANCE3],
[SESREFDATETIME4], [ATTENDANCE4]
FROM
(SELECT
[Reg. number], [Surname],
col + CAST(rn AS varchar(10)) col,
value
FROM
(SELECT
[Reg. number], Surname,
row_number() over(partition by [Reg. number] order by SESREFDATETIME) rn,
SESREFDATETIME,
ATTENDANCE
FROM #Temp) t
CROSS APPLY
(SELECT 'SESREFDATETIME', SESREFDATETIME
UNION ALL
SELECT 'ATTENDANCE', ATTENDANCE) c (col, value)
) x
PIVOT
(max(value)
for col in ([SESREFDATETIME1], [ATTENDANCE1], [SESREFDATETIME2],[ATTENDANCE2], [SESREFDATETIME3], [ATTENDANCE3], [SESREFDATETIME4],[ATTENDANCE4])
) p;

Related

Trying to get DateDiff Based on One Field and Update Another Field

I am trying to update DaysInPeriod with the DateDiff function, based on the change in EFFECTIVESTARTDATE field.
Here is my DLL:
DROP TABLE Reporting_Table
CREATE TABLE Reporting_Table (
Credit_Line_NO Varchar(10),
CURRENCY VARCHAR(3),
AMOUNT INT,
StartDate DATE,
EFFECTIVESTARTDATE DATE,
EXPIRY_DATE Date,
FREQUENCY INT,
CO_CODE VARCHAR(10),
AsOfDate Date,
SOURCEID_REVISED VARCHAR(255),
PID VARCHAR(5),
DaysInPeriod INT
)
INSERT INTO Reporting_Table(CREDIT_LINE_NO,CURRENCY,AMOUNT,STARTDATE,EFFECTIVESTARTDATE,EXPIRY_DATE,FREQUENCY,CO_CODE,ASOFDATE,SourceID_Revised,PID,DaysInPeriod)
VALUES
('1026321','USD','16875','9/30/2017','9/30/2017','9/30/2019','8','US0010001','7/31/2017','','',''),
('1026321','USD','16875','9/30/2017','12/31/2017','9/30/2019','8','US0010001','7/31/2017','','',''),
('1026321','USD','16875','9/30/2017','3/31/2018','9/30/2019','8','US0010001','7/31/2017','','',''),
('1026321','USD','16875','9/30/2017','6/30/2018','9/30/2019','8','US0010001','7/31/2017','','',''),
('1026321','USD','16875','9/30/2017','9/30/2018','9/30/2019','8','US0010001','7/31/2017','','',''),
('1026321','USD','16875','9/30/2017','12/31/2018','9/30/2019','8','US0010001','7/31/2017','','',''),
('1026321','USD','16875','9/30/2017','3/31/2019','9/30/2019','8','US0010001','7/31/2017','','',''),
('1026321','USD','16875','9/30/2017','6/30/2019','9/30/2019','8','US0010001','7/31/2017','','',''),
('1026329','USD','16875','9/30/2017','9/30/2017','9/30/2019','8','US0010001','7/31/2017','','',''),
('1026329','USD','16875','9/30/2017','12/31/2017','9/30/2019','8','US0010001','7/31/2017','','',''),
('1026329','USD','16875','9/30/2017','3/31/2018','9/30/2019','8','US0010001','7/31/2017','','','')
Select *
From Reporting_Table
Select *
From Reporting_Table
I have this SQL:
with cte as
(
select *, rn = row_number() over (partition by Credit_Line_NO,ASOFDATE order by ASOFDATE)
from Reporting_Table
)
Select *
From cte
Basically, when rn=1, DaysInPeriod = 90, and then it should increment by DateDiff(days,rn-1,rn) for every next rn. It should reset based on the change in Credit_Line_NO & ASOFDATE, so I am using:
partition by Credit_Line_NO,ASOFDATE
Here is a sample of what I want to achieve.
I am using SQL Server 2008, so I can't use the Lead/Lag functions. I put together the SQL below, but it doens't execute.
SELECT T1.CREDIT_LINE_NO,
T1.CURRENCY,
T1.AMOUNT,
T1.STARTDATE,
T1.EFFECTIVESTARTDATE,
T1.EXPIRY_DATE,
T1.FREQUENCY,
T1.CO_CODE,
T1.AsOfDate
MIN(T2.EFFECTIVESTARTDATE) AS Date2,
DATEDIFF("D", T1.EFFECTIVESTARTDATE, MIN(T2.EFFECTIVESTARTDATE)) AS DaysDiff
FROM Reporting_Table T1
LEFT JOIN Reporting_Table T2
ON T1.CREDIT_LINE_NO = T2.CREDIT_LINE_NO
AND T2.EFFECTIVESTARTDATE > T1.EFFECTIVESTARTDATE
GROUP BY T1.CREDIT_LINE_NO,
T1.CURRENCY,
T1.AMOUNT,
T1.STARTDATE,
T1.EFFECTIVESTARTDATE,
T1.EXPIRY_DATE,
T1.FREQUENCY,
T1.CO_CODE,
T1.AsOfDate
Finally, I want to run an UPDATE query, or SELECT * INTO NEW_TABLE query.
Your query fails because line 9 T1.AsOfDate is missing a comma. Joining on AND T2.EFFECTIVESTARTDATE > T1.EFFECTIVESTARTDATE creates a 1 to many join which is not necessary. We can imitate a LAG function by applying row_number in a CTE then joining on T1.rn = T2.rn +1.
Edit: I updated your ROW_NUMBER to order by EFFECTIVESTARTDATE since ASOFDATE is a partition column and will always be the same within a window.
Here is the SQL fiddle for this solution.
You can SELECT INTO this result set into a new table or UPDATE an existing table.
WITH cte AS (
SELECT
Credit_Line_NO,
CURRENCY,
AMOUNT,
StartDate,
EFFECTIVESTARTDATE,
EXPIRY_DATE,
FREQUENCY,
CO_CODE,
AsOfDate,
SOURCEID_REVISED,
PID,
DaysInPeriod,
ROW_NUMBER() OVER (PARTITION BY Credit_Line_NO, ASOFDATE ORDER BY EFFECTIVESTARTDATE) AS rn
FROM Reporting_Table
)
SELECT
T1.Credit_Line_NO,
T1.CURRENCY,
T1.AMOUNT,
T1.StartDate,
T1.EFFECTIVESTARTDATE,
T1.EXPIRY_DATE,
T1.FREQUENCY,
T1.CO_CODE,
T1.AsOfDate,
T1.SOURCEID_REVISED,
T1.PID,
CASE
WHEN T1.rn = 1 THEN 90
ELSE DATEDIFF("D", t2.effectivestartdate, t1.effectivestartdate)
END AS DaysInPreiod,
T1.rn
FROM cte AS t1
LEFT JOIN cte AS t2 ON
t1.credit_line_no = t2.credit_line_no
AND t1.rn = t2.rn + 1

sql query that gets the difference between 2 recent rows for every row item that occurs more than once in a table

Sql query that gets the difference between 2 recent rows for every value that occurs more than once in a table.
for example
book value date
A 4 2017-07-17 09:16:44.480
A 2 2017-08-15 10:05:58.273
B 3 2017-04-15 10:05:58.273
C 2 2017-08-15 10:05:58.273
B 3 2017-04-13 10:05:58.273
B 3 2017-04-12 10:05:58.273
should return
A 2
B 0
Here is a solution:
SELECT book, MAX(value) - MIN(value) AS difference FROM (
SELECT book, value, ROW_NUMBER() OVER (PARTITION BY book ORDER BY date DESC) AS rownum FROM t
) AS a WHERE rownum <= 2 GROUP BY book HAVING MAX(rownum) >= 2
And here it is in SQLFiddle
SELECT id_pk FROM [table] GROUP BY [fields you whant to compare by] HAVING COUNT(*) > 1)
this select returns you the list of pk from element that are repited
so, in other select you migth get another Select like
Select * from [table] where id_pk in(
SELECT id_pk FROM [table] GROUP BY [fields you whant to compare by] HAVING COUNT(*) > 1)) limit 2
this is functional, still not good as i'm not analising complexity.
Add a rownumber before calculating:
create table #test ([book] char(1), [value] int, [date] datetime)
insert into #test values ('A', 4, '2017-07-17 09:16:44.480')
insert into #test values ('A', 2, '2017-08-15 10:05:58.273')
insert into #test values ('B', 3, '2017-04-15 10:05:58.273')
insert into #test values ('C', 2, '2017-08-15 10:05:58.273')
insert into #test values ('B', 3, '2017-04-13 10:05:58.273')
insert into #test values ('B', 3, '2017-04-12 10:05:58.273')
;with cte as(
Select ROW_NUMBER () OVER (order by [book], [date] ) as rownumber, *
from #test)
select distinct [1].book, abs(first_value([1].[Value]) over (partition by [1].book order by [1].rownumber desc) - [2].val2) as [Difference]
from cte [1]
inner join
(select rownumber, book, first_value([Value]) over (partition by book order by rownumber desc) as val2
from cte) [2] on [1].book = [2].book and [1].rownumber < [2].rownumber
I would use analytic functions:
;with CTE as (
SELECT book
,value
,LAG(value) OVER (PARTITION BY book ORDER BY date) last_value
,ROW_NUMBER() OVER (PARTITION BY book ORDER BY date DESC) rn
FROM MyTable
)
SELECT book
,value - last_value as value_change
FROM CTE
WHERE rn = 1
AND last_value IS NOT NULL
LAG() was added in SQL Server 2012, but even if you're on a higher version, your database must have the compatibility version set to 110 or higher for them to be available. Here's an alternative that should work on SQL Server 2005 or higher, or a database compatibility 90 or higher.
;with CTE as (
SELECT book
,value
,ROW_NUMBER() OVER (PARTITION BY book ORDER BY date DESC) rn
FROM MyTable
)
SELECT c1.book
c1.value - c2.value as value_change
FROM CTE c1
INNER JOIN CTE c2
ON c1.book = c2.book
WHERE c1.rn = 1
AND c2.rn = 2

Repeat the first date withing a group

I Would like the first date of each group to repeat for the rest of the rows withing each group
You could use window expressions and grouping;
FIRST_VALUE (Transact-SQL)
You would need to partition by your first column. to get the split of A and B.
For example;
with cteTempData
(
[Code]
, [Date]
)
as
(
select 'A',cast('2015-9-4' as date)
union all select 'A','2015-9-4'
union all select 'A','2015-9-4'
union all select 'A','2015-9-16'
union all select 'B','2015-9-16'
union all select 'B','2015-9-22'
union all select 'B','2015-9-22'
union all select 'B','2015-10-26'
union all select 'B','2015-10-30'
)
select
[Code]
, [Date]
, FIRST_VALUE([Date]) over (partition by [Code] order by [Date]) as [First_Date]
from cteTempData
Using the first_value syntax also allows you to work with other columns in that ordered record....
with cteTempData
(
[Code]
, [Date]
, [Comment]
)
as
(
select 'A',cast('2015-9-4' as date),'One'
union all select 'A','2015-9-4','Two'
union all select 'A','2015-9-4','Three'
union all select 'A','2015-9-16','Four'
union all select 'B','2015-9-16','Five'
union all select 'B','2015-9-22','Six'
union all select 'B','2015-9-22','Seven'
union all select 'B','2015-10-26','Eight'
union all select 'B','2015-10-30','Nine'
)
select
[Code]
, [Date]
, FIRST_VALUE([Date]) over (partition by [Code] order by [Date]) as [First_Date]
, FIRST_VALUE([Comment]) over (partition by [Code] order by [Date]) as [First_Comment]
from cteTempData
Use MIN() Over ()
Declare #Table table (Grp varchar(25),Date date)
Insert into #Table values
('A','2015-09-04'),
('A','2015-09-05'),
('A','2015-09-10'),
('B','2015-10-04'),
('B','2015-10-05'),
('B','2015-10-10')
Select *
,GrpDate = min(Date) over (Partition By Grp)
From #Table
Returns
Grp Date GrpDate
A 2015-09-04 2015-09-04
A 2015-09-05 2015-09-04
A 2015-09-10 2015-09-04
B 2015-10-04 2015-10-04
B 2015-10-05 2015-10-04
B 2015-10-10 2015-10-04
You could use MIN with the OVER-clause
SELECT t.ColumnA,
DateCol = MIN( t.DateCol ) OVER ( PARTITION BY t.ColumnA ),
OtherColumns
FROM dbo.TableName t
you can go with a CROSS JOIN or FIRST_VALUE.
Declare #Yourtable table (groupCol varchar(25),firstDate date)
Insert into #Yourtable values
('A','2015-09-04'),
('A','2015-09-05'),
('A','2015-09-10'),
('B','2015-10-04'),
('B','2015-10-05'),
('B','2015-10-10')
SELECT a.*,b.firstDate
FROM #Yourtable a
CROSS JOIN (SELECT groupCol,MIN(firstDate) firstDate
FROM #Yourtable b
GROUP BY groupCol)b
WHERE a.groupCol =b.groupCol
OR
SELECT a.*,FIRST_VALUE(a.firstDate) OVER (PARTITION BY groupCol ORDER BY groupCol ASC) AS firstDate
FROM #Yourtable a

SQL Server 2008 R2 GROUP BY or OVER

I have this table:
ID COLOR TYPE DATE
-------------------------------
1 blue A 2012.02.05
2 white V 2010.10.23
3 white V 2014.03.05
4 black S 2013.02.14
I'd like to select only the ID, but in case of 2nd and 3rd rows I want to select the 3rd row because of its latest DATE value.
I have tried this query but it gives back all the two rows:
SELECT
ID, MAX(DATE) OVER(PARTITION BY COLOR, TYPE)
FROM
TABLE
WHERE
...
How can I select just one column value while I group the rows by other columns, please?
;WITH CTE AS
(
SELECT * , ROW_NUMBER() OVER (PARTITION BY COLOR,[TYPE] ORDER BY [DATE] DESC) rn
FROM TableName
)
SELECT ID
,COLOR
,[TYPE]
,[DATE]
FROM CTE
WHERE rn = 1
OR
SELECT ID
,COLOR
,[TYPE]
,[DATE]
FROM
(
SELECT * , ROW_NUMBER() OVER (PARTITION BY COLOR,[TYPE] ORDER BY [DATE] DESC) rn
FROM TableName
) A
WHERE rn = 1

TSQL - Unpivot multiple columns

How can I unpivot multiple columns in "one"?
Right now I have an unpivot for each column but this creates a lot of empty rows.
See the screenshot please.
At the top you see the input data. At the moment I'm at the table in the middle with this code:
SELECT [ID], [RowNumber], [Year], [Sales] FROM (
SELECT ID, RowNumber, [Sales 2013] as [2013], [Sales 2014] as [2014]
FROM mytable) p UNPIVOT (
[Sales] FOR [Year] IN ([2013], [2014]) )AS unpvt ;
But I think it would be much better to get to the bottom table structure since the actual data contains more columns and more years to deal with.
Here's a Fiddle with the sample data.
Hope you can show me a way to get there.
Thank you.
SELECT [ID],
[RowNumber],
[Year],
Sales,
Budget
FROM mytable
CROSS APPLY (VALUES (2013, [Sales 2013], [Budget 2013]),
(2014, [Sales 2014], [Budget 2014]) )
V([Year], Sales, Budget)
SQL Fiddle
One approach is to repivot after unpivoting - like so:
select [Id], [Year], [Sales], [Budget], [Actual] from
(SELECT [Id],
Left([Colhead], charindex(' ',[Colhead])-1) [Category],
Right([Colhead], len([Colhead])-charindex(' ',[Colhead])) [Year],
[Figures]
FROM (SELECT * FROM mytable) p
UNPIVOT ([Figures] FOR [Colhead] IN
([Sales 2013],[Sales 2014],[Budget 2013],[Budget 2014],[Actual 2013],[Actual 2014])
)
AS unpvt) as u
pivot
(max([Figures]) for [Category] in ([Sales], [Budget], [Actual])) as p
SQLFiddle here.

Resources