Since FUNCCODE is shared between POSCODE and DEVCODE I can't call out both at the same time to eliminate the null values to insert the data into a separate table called JOINT. POSCODE and DEVCODE are FKs. I know there has to be a much easier way of doing this. I spent the last 2 weeks trying to craft a solution... It feels like I don't understand one thing to make this work. Any advice is appreciated.
Table setup
FUNCCODE | POSCODE | DEVCODE
11 1 NULL
12 NULL 1
13 2 NULL
14 NULL 2
The table needs to be rearranged and then inserted into a separate table called JOINT which is setup as:
POSCODE | POSFUNCCODE |DEVCODE | DEVFUNCCODE
1 11 1 12
2 13 2 14
Some of my attempts XD
Each join creates only 2 of the columns I need
SELECT
dbo.POSITION.POSCODE AS POSCODE,
dbo.FUNC.FUNCCODE AS POSFUNCCODE
FROM FUNC
INNER JOIN POSITION ON dbo.POSITION.POSCODE = dbo.FUNC.POSCODE
UNION ALL
SELECT
dbo.DEVICE.DEVCODE AS DEVCODE,
dbo.FUNC.FUNCCODE AS DEVFUNCCODE
FROM FUNC
INNER JOIN DEVICE ON dbo.DEVICE.DEVCODE = dbo.FUNC.DEVCODE
ORDER BY 1;
Only inserts the last row values
DECLARE #DATE DATETIME = GETDATE()
DECLARE #PC INT;
SELECT #PC = POSCODE
FROM func
WHERE poscode != 0
ORDER BY 1;
DECLARE #FCP INT;
SELECT #FCP = FUNCCODE
FROM FUNC
WHERE POSCODE != 0
ORDER BY 1;
DECLARE #DC INT;
SELECT #DC = devcode
FROM func
WHERE devcode != 0
ORDER BY 1;
DECLARE #FCD INT
SELECT #FCD = FUNCCODE
FROM FUNC
WHERE DEVCODE != 0
ORDER BY 1
INSERT INTO JOINT (POSCODE, POSFUNCCODE, DEVCODE, DEVFUNCCODE, JOINTTIME,
JOINTSTATUS)
VALUES (#PC, #FCP, #DC, #FCD, #DATE, 1)
If my understanding of your problem is correct, I think the below query would be a solution.
INSERT INTO JOINT (POSTCODE, DEVCODE, POSFUNCCODE, DEVFUNCCODE)
SELECT
POSTCODE,
DEVCODE,
MAX(CASE
WHEN POSCODE IS NOT NULL THEN FUNCCODE
ELSE NULL
END) POSFUNCCODE,
MAX(CASE
WHEN DEVCODE IS NOT NULL THEN FUNCCODE
ELSE NULL
END) DEVFUNCCODE
FROM FUNC
GROUP BY POSTCODE,DEVCODE
Second version after a better understanding
INSERT INTO JOINT (POSTCODE, DEVCODE, POSFUNCCODE, DEVFUNCCODE)
SELECT
t1.POSTCODE,
t2.DEVCODE,
t1.POSFUNCCODE,
t2.DEVFUNCCODE
(SELECT
POSTCODE,
MAX(CASE
WHEN POSCODE IS NOT NULL THEN FUNCCODE
ELSE NULL
END) POSFUNCCODE
FROM FUNC
GROUP BY POSTCODE) t1
INNER JOIN
(SELECT
DEVCODE,
MAX(CASE
WHEN DEVCODE IS NOT NULL THEN FUNCCODE
ELSE NULL
END) DEVFUNCCODE
FROM FUNC
GROUP BY DEVCODE) t2
ON t1.POSTCODE = t2.DEVCODE
Against my better judgment, I created a loop which inserted the proper values.... I know this is not the correct way to approach this, please excuse me since my experience in SQL is very little. But this corrects the interface issue in the client program. Shout out to #user4219031 for guidance!
DECLARE #DATE DATETIME = GETDATE()
DECLARE #PC INT = 0;
DECLARE #FCP INT = 12;
DECLARE #DC INT = 0;
DECLARE #FCD INT = 13
WHILE ( #PC < 739 )
BEGIN
INSERT INTO JOINT (POSCODE, POSFUNCCODE, DEVCODE, DEVFUNCCODE, JOINTTIME, JOINTSTATUS)
VALUES( #PC, #FCP, #DC, #FCD, #DATE, 1)
SET #PC = #PC + 1
SET #FCP = #FCP +2
SET #DC = #DC + 1
SET #FCD = #FCD + 2
END
EDIT: I changed my query to account for NULL POSCODE or DEVCODE.
SQL Fiddle
MS SQL Server 2017 Schema Setup:
CREATE TABLE t ( FUNCCODE int, POSCODE int, DEVCODE int ) ;
INSERT INTO t (FUNCCODE, POSCODE, DEVCODE)
VALUES
( 11, 1, NULL )
, ( 12, NULL, 1 )
, ( 13, 2, NULL )
, ( 14, NULL, 2 )
, ( 42, NULL, 1 )
, ( 77, NULL, 7 )
, ( 88, NULL, 8 )
, ( 99, 9, NULL )
;
Create New Table And Insert Records
CREATE TABLE ti ( POSCODE int, pos_FUNCCODE int, DEVCODE int, dev_FUNCCODE int ) ;
INSERT INTO ti ( POSCODE, pos_FUNCCODE, DEVCODE, dev_FUNCCODE)
SELECT t1.POSCODE
, t1.FUNCCODE AS pos_FUNCODE
, t2.DEVCODE
, t2.FUNCCODE AS dev_FUNCCODE
FROM t t1
FULL OUTER JOIN t t2 ON t1.POSCODE = t2.DEVCODE
WHERE t1.POSCODE IS NOT NULL OR t2.DEVCODE IS NOT NULL
;
What's In The New Table?:
SELECT * FROM ti
Results:
| POSCODE | pos_FUNCCODE | DEVCODE | dev_FUNCCODE |
|---------|--------------|---------|--------------|
| 1 | 11 | 1 | 12 |
| 1 | 11 | 1 | 42 |
| 2 | 13 | 2 | 14 |
| 9 | 99 | (null) | (null) |
| (null) | (null) | 7 | 77 |
| (null) | (null) | 8 | 88 |
==========ORIGINAL==========
SQL Fiddle
MS SQL Server 2017 Schema Setup:
CREATE TABLE t ( FUNCCODE int, POSCODE int, DEVCODE int ) ;
INSERT INTO t (FUNCCODE, POSCODE, DEVCODE)
VALUES
( 11, 1, NULL )
, ( 12, NULL, 1 )
, ( 13, 2, NULL )
, ( 14, NULL, 2 )
;
Create New Table And Insert Records
CREATE TABLE ti ( POSCODE int, pos_FUNCCODE int, DEVCODE int, dev_FUNCCODE int ) ;
INSERT INTO ti ( POSCODE, pos_FUNCCODE, DEVCODE, dev_FUNCCODE)
SELECT t1.POSCODE
, t1.FUNCCODE AS pos_FUNCODE
, t2.DEVCODE
, t2.FUNCCODE AS dev_FUNCCODE
FROM t t1
INNER JOIN t t2 ON t1.POSCODE = t2.DEVCODE
WHERE t1.POSCODE IS NOT NULL
;
What's In The New Table?:
SELECT * FROM ti
Results:
| POSCODE | pos_FUNCCODE | DEVCODE | dev_FUNCCODE |
|---------|--------------|---------|--------------|
| 1 | 11 | 1 | 12 |
| 2 | 13 | 2 | 14 |
Related
I have a table that shows the entry and exit of items into the warehouse. The Camera 1 and Camera 2 document the entry time and exit time respectively of that item. The cameras then classify the item as it enters and leaves the checkpoint with the help of lasers. Eg: Big box: Class 5, Medium Box: Class 3, Small Box: Class 2.
Sometimes, the cameras classification doesn't match each other. Eg: Classification at entry can be Medium box and on exit can be Small box.
I need to find the number of transactions where the class didn't match for the same TransactionDetail and then a percentage of those class mismatches against all the transaction for a certain time range.
My table looks somewhat like this:
---------------------------------------------------------------------------
| AVDetailID | TransDetailID | AVClassID | CamID | CreatedDate |
---------------------------------------------------------------------------
| 20101522 | 54125478 | 5 | 1 | 2017-05-08 10:15:01:560|
| 20101523 | 54125478 | 5 | 2 | 2017-05-08 10:15:01:620|
| 20101524 | 54125479 | 3 | 1 | 2017-05-08 10:15:03:120|
| 20101525 | 54125479 | 2 | 2 | 2017-05-08 10:15:03:860|
| 20101526 | 54125480 | 4 | 1 | 2017-05-08 10:15:06:330|
| 20101527 | 54125480 | 4 | 2 | 2017-05-08 10:15:06:850|
---------------------------------------------------------------------------
So, in the above case the class changes from 3 to 2 in record 3 and 4. That is one transaction where the class changed. I need to get a percentage of all transactions that where the class changed between each cameras.
The code I've used so far is below. I just need to find a way to get a percentage of the total Transactions.
DECLARE #MinDate DATE = '20170406',
#MaxDate DATE = '20170407';
SELECT COUNT(tdBefore.TransDetailId) TD
--,SUM((COUNT(*) OVER() / allRecords.Count) * 100) AS DiffPercent
FROM AVTransDetail AS tdBefore
INNER JOIN AVTransDetail AS tdAfter
ON tdBefore.TransDetailID = tdAfter.TransDetailID
AND tdBefore.ACClassID = 1
AND tdAfter.ACClassID = 2
CROSS APPLY
(
SELECT COUNT(*) AS [Count]
FROM AVTransDetail
WHERE tdBefore.DateCreated >= #MinDate
AND tdAfter.DateCreated <= #MaxDate
) AS allRecords
WHERE tdBefore.AVCClassId <> tdAfter.AVCClassId
AND tdBefore.DateCreated >= #MinDate
AND tdAfter.DateCreated <= #MaxDate
How do I create a column for percentage of total transactions?
This worked with your sample data.
DECLARE #MinDate DATETIME = '5/8/2017 12:00AM';
DECLARE #MaxDate DATETIME = '5/8/2017 11:59PM';
WITH cam1 AS (
SELECT TransDetailID,AVClassID
FROM AVTransDetail
WHERE CreatedDate BETWEEN #MinDate AND #MaxDate
AND
CamID = 1),
cam2 AS (
SELECT TransDetailID,AVClassID
FROM AVTransDetail
WHERE CreatedDate BETWEEN #MinDate AND #MaxDate
AND
CamID = 2)
SELECT COUNT(*)'Total',SUM(CASE WHEN c1.AVClassID = c2.AVClassID THEN 0 ELSE 1 END)'NonMatch',
SUM(CASE WHEN c1.AVClassID = c2.AVClassID THEN 0 ELSE 1 END) * 100.00/COUNT(*)'Percentage'
FROM cam1 c1
JOIN cam2 c2 ON c1.TransDetailID=c2.TransDetailID
Try the below SQL script.
First we LAG to find the differences. Then, we get each transaction and whether there is a difference. And finally, we get the percentage.
DECLARE #MinDate DATE = '2017/04/06',
#MaxDate DATE = '2017/05/09';
SELECT count(*) AS TotalTransactions
,sum(Change) AS TransactionsWithChange
,(cast(sum(Change) AS FLOAT) / cast(count(*) AS FLOAT)) AS ChangePercent
FROM (
SELECT TransDetailID
,MAX(classChange) AS Change
FROM (
SELECT *
,LAG(AVClassID, 1, AVClassID) OVER (
PARTITION BY TransDetailID ORDER BY AVDetailID
) AS PrevClassId
,CASE
WHEN LAG(AVClassID, 1, AVClassID) OVER (
PARTITION BY TransDetailID ORDER BY AVDetailID
) != AVClassID
THEN 1
ELSE 0
END AS ClassChange
FROM AVTransDetail
where CreatedDate between #MinDate and #MaxDate
) AS CoreData
GROUP BY TransDetailID
) AS ChangeData
Hope this helps.
I added more sample rows to get better result
create table #trans (
AVDetailID int,
TransDetailID int,
AVClassID int,
CamID int,
CreatedDate datetime
)
insert into #trans values
( 20101522, 54125478, 5, 1, '2017-05-08 10:15:01:560'),
( 20101523, 54125478, 5, 2, '2017-05-08 10:15:01:620'),
( 20101524, 54125479, 3, 1, '2017-05-08 10:15:03:120'),
( 20101525, 54125479, 2, 2, '2017-05-08 10:15:03:860'),
( 20101526, 54125480, 4, 1, '2017-05-08 10:15:06:330'),
( 20101527, 54125480, 4, 2, '2017-05-08 10:15:06:850'),
( 20101528, 54125481, 4, 1, '2017-05-08 10:15:07:850'),
( 20101529, 54125481, 5, 2, '2017-05-08 10:15:09:850'),
( 20101530, 54125482, 4, 1, '2017-05-08 10:15:07:850'),
( 20101531, 54125482, 5, 3, '2017-05-08 10:15:09:850')
;with diff as (
-- select records that have different class
select CamID as Ent_CamID, count(*) diff_Count
from #trans ent
outer apply (
select top 1 AVClassID as x_AVClassID, CamID as x_CamID from #trans
where CreatedDate > ent.CreatedDate and TransDetailID = ent.TransDetailID
order by CamID, CreatedDate desc
) ext
where ent.AVClassID <> ext.x_AVClassID
group by ent.CamID, ext.x_CamID
union
select ext.x_CamID as Ext_CamID, count(*) diff_Count
from #trans ent
outer apply (
select top 1 AVClassID as x_AVClassID, CamID as x_CamID from #trans
where CreatedDate > ent.CreatedDate and TransDetailID = ent.TransDetailID
order by CamID, CreatedDate desc
) ext
where ent.AVClassID <> ext.x_AVClassID
group by ent.CamID, ext.x_CamID
)
, perc as (
select Ent_CamID as CamID, sum(diff_Count) Total_Error
, (select count(*)
from #trans where CamID = diff.Ent_CamID
group by CamID) AS Total_Capture
from diff
group by Ent_CamID
)
select CamID, Total_Error, Total_Capture, 100*(Total_Error)/Total_Capture Error_Percentage
from perc
Result:
CamID Total_Error Total_Capture Error_Percentage
1 3 5 60
2 2 4 50
3 1 1 100
Good day, I'm trying to update my table. Because there was an error(s) in my website. first Please check my table. (Penilaian_Header)
IdPenilaian | KodePenilaian | Nip | PositionCode | Total
1613 ----- 1603405 P028 0
1618 ----- 1602999 P028 0
1641 PE0001568 603060 P040 35
1640 PE0001567 1411862 P007 35
as you can see. There are two rows that KodePenilaian empty. So is there any chance to fill it ? so the result will be like this.
IdPenilaian | KodePenilaian | Nip | PositionCode | Total
1613 PE0001570 1603405 P028 0
1618 PE0001569 1602999 P028 0
1641 PE0001568 603060 P040 35
1640 PE0001567 1411862 P007 35
This how i generate KodePenilaian
select case
when right(max(KodePenilaian),7) is null then 'PE0000001'
else ('PE' + RIGHT('0000000' + cast(right(max(KodePenilaian),7) + 1 as nvarchar),7))
end KodePenilaian from Penilaian_Header
and here is there result when i run it
KodePenilaian
PE0001569
Thanks, Sorry for my bad english.
Not really used to sql server 2008
Try something like this:
update Penilaian_Header pen
set pen.KodePenilaian =
(select case
when right(max(newKode.KodePenilaian),7) is null then 'PE0000001'
else ('PE' + RIGHT('0000000' + cast(right(max(newKode.KodePenilaian),7) + 1 as nvarchar),7))
end KodePenilaian
from Penilaian_Header newKode)
where pen.KodePenilain = NULL
if ----- is NULL in your table
You can try this way...
;WITH cte
AS (SELECT *,
MAX(CONVERT(int, REPLACE(KodePenilaian, 'PE000', ''))) OVER () AS MaxNum,
ROW_NUMBER() OVER (ORDER BY kodePenilaian) AS rn
FROM YourTable)
UPDATE cte SET KodePenilaian = concat('PE000', maxnum + rn)
WHERE KodePenilaian IS NULL
Your table
create table YourTable (
IdPenilaian int, KodePenilaian varchar(20), Nip int, PositionCode varchar(10), Total INT)
insert into YourTable
(IdPenilaian , KodePenilaian , Nip , PositionCode , Total) values
( 1613 , NULL , 1603405 ,'P028', 0 )
,( 1618 , NULL , 1602999 ,'P028', 0 )
,( 1641 , 'PE0001568' , 603060 ,'P040', 35 )
,( 1640 , 'PE0001567' , 1411862 ,'P007', 35 )
I tried working with the results i found on here using the pivot answers but i'm not getting it to work. I am trying to join the columns in one table to the rows in another table by date.
I have the following table structure/results.
Holidays table
Date | SusanCalladine | ClaireWillis | FazailaPirbhai
2016-08-22 | 0 | 0 | 1
2016-08-23 | 0 | 1 | 1
2016-08-24 | 0 | 1 | 1
2016-08-25 | 0 | 1 | 1
2016-08-26 | 0 | 0 | 1
Which i am trying to join on date and row to the following (each date has 3 people in seperate rows)
Telephony Table
CallDate | AgentName | InboundCallsAnswered | InboundHandleTime
2016-08-22 | Claire Willis | 0 | 0
2016-08-22 | Fazaila Pirbhai | 36 | 17484
2016-08-22 | Susan Calladine | 0 | 0
2016-08-23 | Claire Willis | 12 | 4250
2016-08-23 | Fazaila Pirbhai | 16 | 23360
2016-08-23 | Susan Calladine | 0 | 0
any help would be much appreciated, thanks in advance
I hope this is what you want. if not do let me know
CREATE TABLE ##Holidaystable
([Date] DATE, SusanCalladine INT, ClaireWillis INT, FazailaPirbhai INT);
INSERT INTO ##Holidaystable VALUES
('2016-08-22', 0, 0, 1),
('2016-08-23', 0, 1, 1),
('2016-08-24', 0, 1, 1),
('2016-08-25', 0, 1, 1),
('2016-08-26', 0, 0, 1)
CREATE TABLE ##TelephonyTable
([CallDate] DATE, AgentName VARCHAR(50), InboundCallsAnswered INT, InboundHandleTime INT);
INSERT INTO ##TelephonyTable VALUES
('2016-08-22' , 'Claire Willis' , 0 , 0),
('2016-08-22' , 'Fazaila Pirbhai' , 36 , 17484),
('2016-08-22' , 'Susan Calladine' , 0 , 0),
('2016-08-23' , 'Claire Willis' , 12 , 4250),
('2016-08-23' , 'Fazaila Pirbhai' , 16 , 23360),
('2016-08-23' , 'Susan Calladine' , 0 , 0)
----Use a CTE for the query as below
;WITH Holiday AS
(SELECT
H.[Date],
T.CallDate
--,T.*
FROM ##Holidaystable H
INNER JOIN ##TelephonyTable T
ON H.[Date]=T.CallDate
)
SELECT * FROM Holiday
PIVOT
(
COUNT([Date]) FOR CallDate IN ([2016-08-22],[2016-08-23])
) AS PV1
You can use UNPIVOT to make rows from columns in Holiday table and join the result with Telephony by Date and AgentName columns.
-- CREATE Holiday Table
CREATE TABLE Holiday
(
Date DATE NOT NULL ,
[Susan Calladine] INT NULL ,
[Claire Willis] INT NULL ,
[Fazaila Pirbhai] INT NULL
);
-- CREATE Telephony Table
CREATE TABLE Telephony
(
CallDate DATE NOT NULL ,
AgentName NVARCHAR(100) NOT NULL ,
InboundCallsAnswered INT NULL ,
InboundHandleTime INT NULL
);
-- Insert rows in Holiday
INSERT INTO Holiday
VALUES ( '2016-08-22', 0, 0, 1 ),
( '2016-08-23', 0, 1, 1 ),
( '2016-08-24', 0, 1, 1 ),
( '2016-08-25', 0, 1, 1 ),
( '2016-08-26', 0, 0, 1 );
-- Insert rows in Telephony
INSERT INTO Telephony
VALUES ( '2016-08-22', 'Claire Willis', 0, 0 ),
( '2016-08-22', 'Fazaila Pirbhai', 36, 17484 ),
( '2016-08-22', 'Susan Calladine', 0, 0 ),
( '2016-08-23', 'Claire Willis', 12, 4250 ),
( '2016-08-23', 'Fazaila Pirbhai', 16, 23360 ),
( '2016-08-23', 'Susan Calladine', 0, 0 );
-- Use UNPIVOT
WITH Hol
AS ( SELECT Date ,
AgentName ,
Calls
FROM ( SELECT *
FROM Holiday
) p UNPIVOT ( Calls FOR AgentName IN ( [Susan Calladine],
[Claire Willis],
[Fazaila Pirbhai] ) ) AS unpvt
)
SELECT Date ,
Hol.AgentName ,
Calls ,
InboundCallsAnswered ,
InboundHandleTime
FROM Hol
LEFT JOIN Telephony t ON Hol.Date = t.CallDate
AND Hol.AgentName = t.AgentName
ORDER BY Date ,
AgentName;
The result will be :
Applies to Microsoft SQL Server 2008 R2.
The problem is
If we have a few dozen Outer Apply (30) then they begin to work pretty slowly. In the middle of the Outer Apply I have something more complicated than a simple select, a view.
Details
I'm writing a sort of attributes assigned to tables (in the database). Generally, a few tables, holds a reference to a table of attributes (key, value).
Pseudo structure looks like this:
DECLARE #Lot TABLE (
LotId INT PRIMARY KEY IDENTITY,
SomeText VARCHAR(8))
INSERT INTO #Lot
OUTPUT INSERTED.*
VALUES ('Hello'), ('World')
DECLARE #Attribute TABLE(
AttributeId INT PRIMARY KEY IDENTITY,
LotId INT,
Val VARCHAR(8),
Kind VARCHAR(8))
INSERT INTO #Attribute
OUTPUT INSERTED.* VALUES
(1, 'Foo1', 'Kind1'), (1, 'Foo2', 'Kind2'),
(2, 'Bar1', 'Kind1'), (2, 'Bar2', 'Kind2'), (2, 'Bar3', 'Kind3')
LotId SomeText
----------- --------
1 Hello
2 World
AttributeId LotId Val Kind
----------- ----------- -------- --------
1 1 Foo1 Kind1
2 1 Foo2 Kind2
3 2 Bar1 Kind1
4 2 Bar2 Kind2
5 2 Bar3 Kind3
I can now run a query such as:
SELECT
[l].[LotId]
, [SomeText]
, [Oa1].[AttributeId]
, [Oa1].[LotId]
, 'Kind1Val' = [Oa1].[Val]
, [Oa1].[Kind]
, [Oa2].[AttributeId]
, [Oa2].[LotId]
, 'Kind2Val' = [Oa2].[Val]
, [Oa2].[Kind]
, [Oa3].[AttributeId]
, [Oa3].[LotId]
, 'Kind3Val' = [Oa3].[Val]
, [Oa3].[Kind]
FROM #Lot AS l
OUTER APPLY(SELECT * FROM #Attribute AS la WHERE la.[LotId] = l.[LotId] AND la.[Kind] = 'Kind1') AS Oa1
OUTER APPLY(SELECT * FROM #Attribute AS la WHERE la.[LotId] = l.[LotId] AND la.[Kind] = 'Kind2') AS Oa2
OUTER APPLY(SELECT * FROM #Attribute AS la WHERE la.[LotId] = l.[LotId] AND la.[Kind] = 'Kind3') AS Oa3
LotId SomeText AttributeId LotId Kind1Val Kind AttributeId LotId Kind2Val Kind AttributeId LotId Kind3Val Kind
----------- -------- ----------- ----------- -------- -------- ----------- ----------- -------- -------- ----------- ----------- -------- --------
1 Hello 1 1 Foo1 Kind1 2 1 Foo2 Kind2 NULL NULL NULL NULL
2 World 3 2 Bar1 Kind1 4 2 Bar2 Kind2 5 2 Bar3 Kind3
The simple way to get the pivot table of attribute values and results for Lot rows that do not have attribute such a Kind3.
I know Microsoft PIVOT and it is not simple and do not fits here.
Finally, what will be faster and will give the same results?
In order to get the result you can unpivot and then pivot the data.
There are two ways that you can perform this. First, you can use the UNPIVOT and the PIVOT function:
select *
from
(
select LotId,
SomeText,
col+'_'+CAST(rn as varchar(10)) col,
value
from
(
select l.LotId,
l.SomeText,
cast(a.AttributeId as varchar(8)) attributeid,
cast(a.LotId as varchar(8)) a_LotId,
a.Val,
a.Kind,
ROW_NUMBER() over(partition by l.lotid order by a.attributeid) rn
from #Lot l
left join #Attribute a
on l.LotId = a.LotId
) src
unpivot
(
value
for col in (attributeid, a_Lotid, val, kind)
) unpiv
) d
pivot
(
max(value)
for col in (attributeid_1, a_LotId_1, Val_1, Kind_1,
attributeid_2, a_LotId_2, Val_2, Kind_2,
attributeid_3, a_LotId_3, Val_3, Kind_3)
) piv
See SQL Fiddle with Demo.
Or starting in SQL Server 2008+, you can use CROSS APPLY with a VALUES clause to unpivot the data:
select *
from
(
select LotId,
SomeText,
col+'_'+CAST(rn as varchar(10)) col,
value
from
(
select l.LotId,
l.SomeText,
cast(a.AttributeId as varchar(8)) attributeid,
cast(a.LotId as varchar(8)) a_LotId,
a.Val,
a.Kind,
ROW_NUMBER() over(partition by l.lotid order by a.attributeid) rn
from #Lot l
left join #Attribute a
on l.LotId = a.LotId
) src
cross apply
(
values ('attributeid', attributeid),('LotId', a_LotId), ('Value', Val), ('Kind', Kind)
) c (col, value)
) d
pivot
(
max(value)
for col in (attributeid_1, LotId_1, Value_1, Kind_1,
attributeid_2, LotId_2, Value_2, Kind_2,
attributeid_3, LotId_3, Value_3, Kind_3)
) piv
See SQL Fiddle with Demo.
The unpivot process takes the multiple columns for each LotID and SomeText and converts it into rows giving the result:
| LOTID | SOMETEXT | COL | VALUE |
--------------------------------------------
| 1 | Hello | attributeid_1 | 1 |
| 1 | Hello | LotId_1 | 1 |
| 1 | Hello | Value_1 | Foo1 |
| 1 | Hello | Kind_1 | Kind1 |
| 1 | Hello | attributeid_2 | 2 |
I added a row_number() to the inner subquery to be used to create the new column names to pivot. Once the names are created the pivot can be applied to the new columns giving the final result
This could also be done using dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(col+'_'+rn)
from
(
select
cast(ROW_NUMBER() over(partition by l.lotid order by a.attributeid) as varchar(10)) rn
from Lot l
left join Attribute a
on l.LotId = a.LotId
) t
cross apply (values ('attributeid', 1),
('LotId', 2),
('Value', 3),
('Kind', 4)) c (col, so)
group by col, rn, so
order by rn, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT LotId,
SomeText,' + #cols + '
from
(
select LotId,
SomeText,
col+''_''+CAST(rn as varchar(10)) col,
value
from
(
select l.LotId,
l.SomeText,
cast(a.AttributeId as varchar(8)) attributeid,
cast(a.LotId as varchar(8)) a_LotId,
a.Val,
a.Kind,
ROW_NUMBER() over(partition by l.lotid order by a.attributeid) rn
from Lot l
left join Attribute a
on l.LotId = a.LotId
) src
cross apply
(
values (''attributeid'', attributeid),(''LotId'', a_LotId), (''Value'', Val), (''Kind'', Kind)
) c (col, value)
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
All three versions will give the same result:
| LOTID | SOMETEXT | ATTRIBUTEID_1 | LOTID_1 | VALUE_1 | KIND_1 | ATTRIBUTEID_2 | LOTID_2 | VALUE_2 | KIND_2 | ATTRIBUTEID_3 | LOTID_3 | VALUE_3 | KIND_3 |
-----------------------------------------------------------------------------------------------------------------------------------------------------------
| 1 | Hello | 1 | 1 | Foo1 | Kind1 | 2 | 1 | Foo2 | Kind2 | (null) | (null) | (null) | (null) |
| 2 | World | 3 | 2 | Bar1 | Kind1 | 4 | 2 | Bar2 | Kind2 | 5 | 2 | Bar3 | Kind3 |
I am trying to select data based on some parameters passed to my stored procedure. I have problems with the age, I am trying to do something like this:
If my stored procedure parameter #Age = 1 then I select age between 15 to 18, #Age = 2 then 19 - 25..., apparently this is incorrect, anyone can help. Thanks.:
SELECT
User
FROM
[Member] m
WHERE
((m.Gender = #Gender) or #Gender IS NULL)
and ((DATEDIFF(hour,m.DOB,GETDATE())/8766) Between
CASE
WHEN #Age = 1 THEN (SELECT DATEDIFF(hour, m.DOB, GETDATE())/8766 WHERE (SELECT DATEDIFF(hour, m.DOB, GETDATE())/8766) between 15 and 18)
WHEN #Age = 2 THEN (SELECT DATEDIFF(hour,m.DOB,GETDATE())/8766 WHERE (SELECT DATEDIFF(hour,m.DOB,GETDATE())/8766) between 19 and 25)
END)
I think this is what you are after (probably with some superfluous parenthesis):
Select
[User]
From
[Member] m
Where (
(m.Gender = #Gender) or
#Gender Is Null
) And (
(#Age = 1 And DateDiff(hour, m.Dob, GetDate())/8766 Between 15 and 18) Or
(#Age = 2 And DateDiff(hour, m.Dob, GetDate())/8766 Between 19 and 25)
)
If you've got a lot of clauses, it might be easier to read as (assuming a MemberID Primary Key)
Select
[User]
From
[Member] m
Inner Join (
Select
MemberID,
DateDiff(hour, m.Dob, GetDate())/8766 As Years
From
[Member]
) As y
On m.MemberID = y.MemberID
Where (
(m.Gender = #Gender) or
#Gender Is Null
) And (
(#Age = 1 And y.Year Between 15 and 18) Or
(#Age = 2 And y.Year Between 19 and 25)
)
Even better, you could add the ranges to a separate table called AgeRanges
+-------+------------+----------+
| AgeID | StartYears | EndYears |
+-------+------------+----------+
| 1 | 15 | 18 |
| 2 | 19 | 25 |
| ... | ... | ... |
+-------+------------+----------+
Select
[User]
From
[Member] m
Inner Join
[AgeRanges] a
On DateDiff(hour, m.Dob, GetDate())/8766 Between a.StartYears and a.EndYears And
a.AgeID = #Age
You could also make DateDiff(hour, m.Dob, GetDate())/8766 a computed column on your members table to simplify things (and make indexing possible if performance became an issue).