update of a column based on max date and group by - sql

i have three tables orders, orders_delivered, orders_delivered_sta
and the data in the three tables look like
table orders
orders_id
10
11
12
13
table orders_delivered
orders_delivered_id orders_id
10 1000
10 1001
11 1002
12 1003
12 1004
13 1005
13 1006
13 1007
table orders_delivered_sta
orders_delivered_sta_id orders_delivered_id date now_ind
1 1000 02/11/2011 0
2 1000 01/10/2006 0
3 1000 09/13/2011 0
4 1001 01/19/2010 0
5 1001 02/21/2011 0
6 1002 02/11/2009 0
7 1002 08/27/2010 0
8 1003 07/15/2012 0
9 1004 03/09/2007 0
10 1010 10/01/2010 0
11 1011 03/27/2011 0
12 1012 07/25/2010 0
13 1013 09/18/2004 0
so i need to update orders_delivered_sta table such that now_ind should be 1 for the max date of one orders_delivered_id
like for one orders_delivered_id 1000 the max date is 09/13/2011 for this set of orders_delivered_id and date (1000,09/13/2011) the now_ind should be 1 and if the column orders_delivered_id has one and only one id then that should be changed to 1
there is some data in orders_delivered_sta table which are not in orders and orders_delivered tables those need not to be changed. the orders_delivered_id which are in oreders_delivered table only needs to change
so the desired output should look like
table orders_delivered_sta
orders_delivered_sta_id orders_delivered_id date now_ind
1 1000 02/11/2011 0
2 1000 01/10/2006 0
3 1000 09/13/2011 1
4 1001 01/19/2010 0
5 1001 02/21/2011 1
6 1002 02/11/2009 0
7 1002 08/27/2010 1
8 1003 07/15/2012 1
9 1004 03/09/2007 1
10 1010 10/01/2010 0
11 1011 03/27/2011 0
12 1012 07/25/2010 0
13 1013 09/18/2004 0
table structure:
create table orders
(
order_id int primary key
)
insert into orders select 10
insert into orders select 11
insert into orders select 12
insert into orders select 13
create table orders_delivered
(
orders_delivered_id int primary key,
orders_id int FOREIGN KEY(orders_id)REFERENCES orders (orders_id)
)
insert into orders_delivered select 1000,10
insert into orders_delivered select 1001,10
insert into orders_delivered select 1002,11
insert into orders_delivered select 1003,12
insert into orders_delivered select 1004,12
insert into orders_delivered select 1005,13
insert into orders_delivered select 1006,13
insert into orders_delivered select 1007,13
create table orders_delivered_sta
(
orders_delivered_sta_id int primary key,
orders_delivered_id int FOREIGN KEY(orders_delivered_id)REFERENCES orders_delivered (orders_delivered_id),
date char(10),
now_ind int
)
insert into orders_delivered_sta select 1,1000,'02/11/2011', 0
insert into orders_delivered_sta select 2,1000,'01/10/2006', 0
insert into orders_delivered_sta select 3,1000,'09/13/2011', 0
insert into orders_delivered_sta select 4,1001,'01/19/2010', 0
insert into orders_delivered_sta select 5,1001,'02/21/2011', 0
insert into orders_delivered_sta select 6,1002,'02/11/2009', 0
insert into orders_delivered_sta select 7,1002,'08/27/2010', 0
insert into orders_delivered_sta select 8,1003,'07/15/2012', 0
insert into orders_delivered_sta select 9,1004,'03/09/2007', 0
insert into orders_delivered_sta select 10,1010,'10/01/2010', 0
insert into orders_delivered_sta select 11,1011,'03/27/2011', 0
insert into orders_delivered_sta select 12,1012,'07/25/2010', 0
insert into orders_delivered_sta select 13,1013,'09/18/2004', 0

You could use a CTE and a window MAX():
;
WITH max_dates AS (
SELECT
*,
max_date = MAX(date) OVER (PARTITION BY orders_delivered_id)
FROM orders_delivered_sta
WHERE orders_delivered_id IN (SELECT orders_delivered_id FROM orders_delivered)
)
UPDATE max_dates
SET now_ind = 1
WHERE date = max_date
References:
WITH common_table_expression (Transact-SQL)
OVER Clause (Transact-SQL)

This is the query in MySQL, but translating it to SQL-Server should be straight forward as I am using plain SQL. Notice I have changed the date to be in a different form (YYYY-MM-DD) to avoid castings from string to date.
update t3
set t3.now_ind = 1
where t3.orders_delivered_sta_id in (
select distinct t1.orders_delivered_sta_id from t1
left join (
select t2.orders_delivered_id, max(t2.adate) as MaxDate from t2
group by t2.orders_delivered_id
) t2 on (t1.orders_delivered_id = t2.orders_delivered_id) and (t1.adate = t2.MaxDate)
where t2.orders_delivered_id is not null
) and exists (
select * from o1
join od1 on (o1.order_id = od1.orders_delivered_id)
where (t3.orders_delivered_id = od1.orders_id)
)
Here is an example
Hope this helps
PS: You did need those 3 tables... I'll read questions better next time :)

Try this:
UPDATE orders_delivered_sta
SET now_ind = 1
WHERE orders_delivered_sta_id IN(
SELECT orders_delivered_sta_id
FROM (
SELECT orders_delivered_sta_id,
ROW_NUMBER() OVER(PARTITION BY orders_delivered_id ORDER BY date DESC) AS num
FROM orders_delivered_sta) AS T
WHERE T.num = 1)

Related

SQL get consecutive days ignoring weekend

I have a table with following format:
ID ID1 ID2 DATE
1 1 1 2018-03-01
2 1 1 2018-03-02
3 1 1 2018-03-05
4 1 1 2018-03-06
5 1 1 2018-03-07
6 2 2 2018-03-05
7 2 2 2018-03-05
8 2 2 2018-03-06
9 2 2 2018-03-07
10 2 2 2018-03-08
From this table I have to get all records where ID1 and ID2 are the same in that column and where DATE is 5 consecutive work days (5 dates in a row, ignoring missing dates for Saturday/Sunday; ignore holidays).
I have really no idea how to achieve this. I did search around, but couldn't find anything that helped me. So my question is, how can I achieve following output?
ID ID1 ID2 DATE
1 1 1 2018-03-01
2 1 1 2018-03-02
3 1 1 2018-03-05
4 1 1 2018-03-06
5 1 1 2018-03-07
SQLFiddle to mess around
Assuming you have no duplicates and work is only on weekdays, then there is a simplish solution for this particular case. We can identify the date 4 rows ahead. For a complete week, it is either 4 days ahead or 6 days ahead:
select t.*
from (select t.*, lead(dat, 4) over (order by id2, dat) as dat_4
from t
) t
where datediff(day, dat, dat_4) in (4, 6);
This happens to work because you are looking for a complete week.
Here is the SQL Fiddle.
select t.* from
(select id1,id2,count(distinct dat) count from t
group by id1,id2
having count(distinct dat)=5) t1 right join
t
on t.id1=t1.id1 and t.id2=t1.id2
where count=5
Check this-
Dates of Two weeks with 10 valid dates
http://sqlfiddle.com/#!18/76556/1
Dates of Two weeks with 10 non-unique dates
http://sqlfiddle.com/#!18/b4299/1
and
Dates of Two weeks with less than 10 but unique
http://sqlfiddle.com/#!18/f16cb/1
This query is very verbose without LEAD or LAG and it is the best I could do on my lunch break. You can probably improve on it given the time.
DECLARE #T TABLE
(
ID INT,
ID1 INT,
ID2 INT,
TheDate DATETIME
)
INSERT #T SELECT 1,1,1,'03/01/2018'
INSERT #T SELECT 2,1,1,'03/02/2018'
INSERT #T SELECT 3,1,1,'03/05/2018'
INSERT #T SELECT 4,1,1,'03/06/2018'
INSERT #T SELECT 5,1,1,'03/07/2018'
--INSERT #T SELECT 5,1,1,'03/09/2018'
INSERT #T SELECT 6,2,2,'03/02/2018'
INSERT #T SELECT 7,2,2,'03/05/2018'
INSERT #T SELECT 8,2,2,'03/05/2018'
--INSERT #T SELECT 9,2,2,'03/06/2018'
INSERT #T SELECT 10,2,2,'03/07/2018'
INSERT #T SELECT 11,2,2,'03/08/2018'
INSERT #T SELECT 12,2,2,'03/15/2018'
INSERT #T SELECT 13,1,1,'04/01/2018'
INSERT #T SELECT 14,1,1,'04/02/2018'
INSERT #T SELECT 15,1,1,'04/05/2018'
--SELECT * FROM #T
DECLARE #LowDate DATETIME = DATEADD(DAY,-1,(SELECT MIN(TheDate) FROM #T))
DECLARE #HighDate DATETIME = DATEADD(DAY,1,(SELECT MAX(TheDate) FROM #T))
DECLARE #DaysThreshold INT = 5
;
WITH Dates AS
(
SELECT DateValue=#LowDate
UNION ALL
SELECT DateValue + 1 FROM Dates
WHERE DateValue + 1 < #HighDate
),
Joined AS
(
SELECT * FROM Dates LEFT OUTER JOIN #T T ON T.TheDate=Dates.DateValue
),
Calculations AS
(
SELECT
ID=MAX(J1.ID),
J1.ID1,J1.ID2,
J1.TheDate,
LastDate=MAX(J2.TheDate),
LastDateWasWeekend = CASE WHEN ((DATEPART(DW,DATEADD(DAY,-1,J1.TheDate) ) + ##DATEFIRST) % 7) NOT IN (0, 1) THEN 0 ELSE 1 END,
Offset = DATEDIFF(DAY,MAX(J2.TheDate),J1.TheDate)
FROM
Joined J1
LEFT OUTER JOIN Joined J2 ON J2.ID1=J1.ID1 AND J2.ID2=J1.ID2 AND J2.TheDate<J1.TheDate
WHERE
NOT J1.ID IS NULL
GROUP BY J1.ID1,J1.ID2,J1.TheDate
)
,FindValid AS
(
SELECT
ID,ID1,ID2,TheDate,
IsValid=CASE
WHEN LastDate=TheDate THEN 0
WHEN LastDate IS NULL THEN 1
WHEN Offset=1 THEN 1
WHEN Offset>3 THEN 0
WHEN Offset<=3 THEN
LastDateWasWeekend
END
FROM
Calculations
UNION
SELECT DISTINCT ID=NULL,ID1,ID2, TheDate=#HighDate,IsValid=0 FROM #T
),
FindMax As
(
SELECT
This.ID,This.ID1,This.ID2,This.TheDate,MaxRange=MIN(Next.TheDate)
FROM
FindValid This
LEFT OUTER JOIN FindValid Next ON Next.ID2=This.ID2 AND Next.ID1=This.ID1 AND This.TheDate<Next.TheDate AND Next.IsValid=0
GROUP BY
This.ID,This.ID1,This.ID2,This.TheDate
),
FindMin AS
(
SELECT
This.ID,This.ID1,This.ID2,This.TheDate,This.MaxRange,MinRange=MIN(Next.TheDate)
FROM
FindMax This
LEFT OUTER JOIN FindMax Next ON Next.ID2=This.ID2 AND Next.ID1=This.ID1 AND This.TheDate<Next.MaxRange-- AND Next.IsValid=0 OR Next.TheDate IS NULL
GROUP BY
This.ID,This.ID1,This.ID2,This.TheDate,This.MaxRange
)
,Final AS
(
SELECT
ID1,ID2,MinRange,MaxRange,SequentialCount=COUNT(*)
FROM
FindMin
GROUP BY
ID1,ID2,MinRange,MaxRange
)
SELECT
T.ID,
T.ID1,
T.ID2,
T.TheDate
FROM #T T
INNER JOIN Final ON T.TheDate>= Final.MinRange AND T.TheDate < Final.MaxRange AND T.ID1=Final.ID1 AND T.ID2=Final.ID2
WHERE
SequentialCount>=#DaysThreshold
OPTION (MAXRECURSION 0)

Display results of multiple count in a sql query

There are two table:
Table persons:
P_id Name BirthDate
1 N1 2016-08-02
2 N2 2015-05-02
3 N3 2013-06-01
4 N4 2014-01-09
Table visited:(p_id is foreign key to table persons)
Id. Visitor_id. P_id. Visit_date
1 10 1 2017-03-05
2 11 2 2017-01-01
3 10 2 2017-02-03
4 12 3 2016-05-07
5 11 4 2016-04-09
6 10 1 2017-04-09
We are going to get the count of visited persons who their old are under 1, between 1 and 2, between 2 and 3 at date of visit_date by each visitor_id.
The results like :
Visitor_id Under_one Bet_one_two Bet_two_three
10 2 1 0
11 0 1 1
12 0 0 1
Could anyone help me how write a query in sql server for getting the results?
In above results, 0,1,2 means that we subtract of two date(visited_date - birthdate), for example : the result of 2013/03/05 - 2011/06/07 is between 1 and 2
you can try a pivot query like below
select
visitor_id,
Under_one=ISNULL([0],0),
Bet_one_two=ISNULL([1],0),
Bet_two_three=ISNULL([2],0)
from
(
select visitor_id, datediff(m,BirthDate,visit_date)/12 age_in_years,count(1) count from persons p join
visited v on p.p_id=v.p_id
group by visitor_id,datediff(m,BirthDate,visit_date)/12
) src
pivot
(
max(count) for age_in_years in ([0],[1],[2])
)p
see live demo
/*
DROP TABLE Visited
DROP TABLE Persons
DROP TABLE #Data
DROP TABLE #Results
*/
CREATE TABLE Persons
(
[P_id.] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Name] NVARCHAR(2),
BirthDate DATETIME
)
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N1','2016-08-02')
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N2','2015-05-02')
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N3','2013-06-01')
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N4','2014-01-09')
GO
CREATE TABLE Visited
(
[ID.] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Visitor_id.] INT,
[P_id.] INT REFERENCES Persons,
Visit_date DATETIME
)
GO
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (10,1,'2017-03-05')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (11,2,'2017-01-01')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (10,2,'2017-02-03')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (12,3,'2016-05-07')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (11,4,'2016-04-09')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (10,1,'2017-04-09')
GO
SELECT [Visitor_id.],
CASE WHEN DATEPART(YY,v.visit_date-p.birthdate) = 1900 THEN 'Under_one'
WHEN DATEPART(YY,v.visit_date-p.birthdate) = 1901 THEN 'Bet_one_two'
WHEN DATEPART(YY,v.visit_date-p.birthdate) = 1902 THEN 'Bet_two_three'
END AS Age,
COUNT([Visitor_id.]) AS Number
INTO #Data
FROM Persons p INNER JOIN Visited v on p.[P_id.]=v.[P_id.]
GROUP BY [Visitor_id.],DATEPART(YY,v.visit_date-p.birthdate)
GO
CREATE TABLE #Results
(
Visitor_ID INT,
Under_one INT,
Bet_one_two INT,
Bet_two_three INT
)
GO
DECLARE #Visitor_id INT = (SELECT MIN([Visitor_id.]) FROM #Data)
WHILE #Visitor_id <= (SELECT MAX([Visitor_id.]) FROM #Data)
BEGIN
INSERT INTO #Results VALUES
(
(SELECT #Visitor_id)
,
(SELECT Number FROM #Data WHERE [Visitor_id.]=#Visitor_id AND Age = 'Under_one')
,
(SELECT Number FROM #Data WHERE [Visitor_id.]=#Visitor_id AND Age = 'Bet_one_two')
,
(SELECT Number FROM #Data WHERE [Visitor_id.]=#Visitor_id AND Age = 'Bet_two_three')
)
SET #Visitor_id = #Visitor_id + 1
END
UPDATE #Results SET Under_one = 0 WHERE Under_one IS NULL
GO
UPDATE #Results SET Bet_one_two = 0 WHERE Bet_one_two IS NULL
GO
UPDATE #Results SET Bet_two_three = 0 WHERE Bet_two_three IS NULL
GO
SELECT * FROM #Results
How about something like:
CREATE TABLE persons
(p_id int, name varchar(5), birthday date);
INSERT INTO persons
(p_id, name, birthday)
VALUES
(1, 'N1', '2016-08-02'),
(2, 'N2', '2015-05-02'),
(3, 'N3', '2013-06-01'),
(4, 'N4', '2014-01-09');
CREATE TABLE visited
(id int, visitor_id int,p_id int, visit_date date)
;
INSERT INTO visited(id, visitor_id,p_id, visit_date)
VALUES
(1,10,1,'2017-03-05'),
(2,11,2,'2017-01-01'),
(3,10,2,'2017-02-03'),
(4,12,3,'2016-05-07'),
(5,11,4,'2016-04-09'),
(6,10,1,'2017-04-09');
WITH visitAge(visitor_ID, VisitAge) AS
(SELECT
v.visitor_ID, DateDiff(Year, birthday,visit_date) as VisitAge
FROM visited v
INNER JOIN persons p on v.p_ID = p.p_ID
)
SELECT
visitor_ID,
SUM(CASE WHEN VisitAge < 1 THEN 1 ELSE 0 END ) AS under_one,
SUM(CASE WHEN VisitAge >= 1 AND VisitAge < 2 THEN 1 ELSE 0 END ) AS Bet_one_two,
SUM(CASE WHEN VisitAge >= 2 AND VisitAge < 3 THEN 1 ELSE 0 END ) AS Bet_two_three
FROM
visitAge
GROUP BY visitor_ID;
not durable solution...but for what I see in the question...it's a start for you....
SQL Fiddle link

Distinct columns having the max date value

Let's say I have a table:
LpOpenTradeId LPSource SymbolId Volume CreatedUser CreatedDate
1 2 1 10.00 2 2015-12-11 00:00:00.000
2 2 4 12.00 2 2015-12-11 00:00:00.000
3 2 1 10.00 2 2015-12-11 10:53:00.000
4 2 3 1.00 2 2015-12-11 18:03:14.676
5 2 5 1.00 2 2015-12-14 09:38:33.691
6 2 3 2.00 2 2015-12-14 09:39:30.305
7 2 4 13.00 2 2015-12-14 09:43:13.916
8 3 1 15.00 2 2015-12-11 10:53:00.000
I want to select the distinct LPSource and SymbolId columns with the Volumes having max CreatedDates. I mean the target result set is:
LPSource SymbolId Volume CreatedDate
2 1 10.00 2015-12-11 10:53:00.000
2 4 13.00 2015-12-14 09:43:13.916
2 3 2.00 2015-12-14 09:39:30.305
2 5 1.00 2015-12-14 09:38:33.691
3 1 15.00 2015-12-11 10:53:00.000
How can I express myself to have this resultset in T-SQL?
Thanks,
You can use ROW_NUMBER:
SELECT LPSource, SymbolId, Volume, CreatedDate
FROM (
SELECT LPSource, SymbolId, Volume, CreatedDate,
ROW_NUMBER() OVER (PARTITION BY LPSource, SymbolId
ORDER BY CreatedDate DESC) AS rn
FROM mytable) AS t
WHERE t.rn = 1
In case of CreatedDate ties, i.e. more than one records sharing the same maximum CreatedDate value within the same LPSource, SymbolId partition, the above query will randomly select one record. You can use RANK to select all records in such a case.
IF OBJECT_ID('Tabel1','U') IS NOT NULL
BEGIN
DROP TABLE Tabel1
END
CREATE TABLE Tabel1 (LpOpenTradeId INT
,LPSource INT
,SymbolId INT
,Volume DECIMAL(10,2)
,CreatedUser INT
,CreatedDate DATETIME2
)
INSERT INTO Tabel1 VALUES (1,2,1,10,2,'2015-12-11 00:00:00.000');
INSERT INTO Tabel1 VALUES (2,2,4,12,2,'2015-12-11 00:00:00.000');
INSERT INTO Tabel1 VALUES (3,2,1,10,2,'2015-12-11 10:53:00.000');
INSERT INTO Tabel1 VALUES (4,2,3,1,2,'2015-12-11 18:03:14.676');
INSERT INTO Tabel1 VALUES (5,2,5,1,2,'2015-12-14 09:38:33.691');
INSERT INTO Tabel1 VALUES (6,2,3,2,2,'2015-12-14 09:39:30.305');
INSERT INTO Tabel1 VALUES (7,2,4,13,2,'2015-12-14 09:43:13.916');
INSERT INTO Tabel1 VALUES (8,3,1,15,2,'2015-12-11 10:53:00.000');
SELECT DISTINCT t1.LPSource
,t1.SymbolId
,t1.Volume
,t1.CreatedDate
FROM Tabel1 t1
JOIN (
SELECT LPSource
,SymbolId
,MAX(CreatedDate) AS CreatedDate
FROM Tabel1
GROUP BY LPSource
,SymbolId
) t2 on t2.LPSource = t1.LPSource AND t2.SymbolId = t1.SymbolId AND t2.CreatedDate = t1.CreatedDate
The JOIN part :
SELECT LPSource
,SymbolId
,MAX(CreatedDate) AS CreatedDate
FROM Tabel1
GROUP BY LPSource
,SymbolId
get's the latest LPSource and SymbolId. You then JOIN your initial table with all the columns in this temporary table (t2) giving you the result needed.t1.LPSource, t1.SymbolId, t1.Volume, t1.CreatedDate
Use NOT EXISTS to return a row if no other row with same LPSource/SymbolId has (1) a later CreatedDate, or (2) same CreatedDate but a higher Volume.
select distinct LPSource, SymbolId, Volume, CreatedDate
from tablename t1
where not exists (select 1 from tablename t2
where t2.LPSource = t1.LPSource
and t2.SymbolId = t1.SymbolId
and (t2.CreatedDate > t1.CreatedDate
or (t2.CreatedDate = t1.CreatedDate and
t2.volume > t1.volume))

How to count daily sales of salesman and show dates as a column in SQL QUERY

I have a sales table like this
salesmanID customerID productID date
1 100 1 20.02.2015
1 101 2 20.02.2015
1 102 4 21.02.2015
2 122 6 20.02.2015
2 120 2 22.02.2015
3 150 1 23.02.2015
3 144 8 23.02.2015
3 122 4 24.02.2015
and I want to count of daily sales for each salesman day by day between min and max dates of given two dates(in this sample 20-02-2015 and 24-02-2015) like this,
salesmanID 20.02.2015 21.02.2015 22.02.2015 23.02.2015 24.02.2015
1 2 1 0 0 0
2 1 0 1 0 0
3 0 0 0 2 1
How can I do this in SQL query?
you have to use PIVOT and count of SalesmanID
declare #temp table
(salesmanID int, customerID int, productID int, dates VARCHAR(10))
insert into #temp values (1,100,1,CONVERT(VARCHAR(10), '20.02.2015', 104) )
insert into #temp values (1,101,2,CONVERT(VARCHAR(10), '20.02.2015', 104) )
insert into #temp values (1,102,4,CONVERT(VARCHAR(10), '21.02.2015', 104) )
insert into #temp values (2,122,6,CONVERT(VARCHAR(10), '20.02.2015', 104) )
insert into #temp values (2,120,2,CONVERT(VARCHAR(10), '22.02.2015', 104) )
insert into #temp values (3,150,1,CONVERT(VARCHAR(10), '23.02.2015', 104) )
insert into #temp values (3,144,8,CONVERT(VARCHAR(10), '23.02.2015', 104) )
insert into #temp values (3,122,4,CONVERT(VARCHAR(10), '24.02.2015', 104) )
--QUERY
SELECT *
FROM (SELECT salesmanID, salesmanID as id,dates
FROM #temp) as s
PIVOT
(
count(id)
FOR dates IN ([20.02.2015], [21.02.2015], [22.02.2015], [23.02.2015], [24.02.2015])
)AS pivots
RESULT

Create indexed view

My table structure is below :
MyTable (ID Int, AccID1 Int, AccID2 Int, AccID3 int)
ID AccID1 AccID2 AccID3
---- -------- -------- --------
1 12 2 NULL
2 4 12 1
3 NULL NULL 5
4 7 NULL 1
I want to create indexed view with below output :
ID Level Value
---- ----- -------
1 1 12
1 2 2
2 1 4
2 2 12
2 3 1
3 3 5
4 1 7
4 3 1
EDIT :
My table is very huge and I want to have above output.
I can Get my query such as below :
Select ID,
Case StrLevel
When 'AccID1' Then 1
When 'AccID2' Then 2
Else 3
End AS [Level],
AccID as Value
From (
Select A.ID, A.AccID1, A.AccID2, A.AccID3
From MyTable A
)as p
UNPIVOT (AccID FOR [StrLevel] IN (AccID1, AccID2, AccID3)) AS unpvt
or
Select *
from (
select MyTable.ID,
num.n as [Level],
Case Num.n
When 1 Then MyTable.AccID1
When 2 Then MyTable.AccID2
Else MyTable.AccID3
End AS AccID
from myTable
cross join (select 1
union select 2
union select 3)Num(n)
)Z
Where Z.AccID IS NOT NULL
or
Select A.ID,
2 AS [Level],
A.AccID1 AS AccID
From MyTable A
Where A.AccID1 IS NOT NULL
Union
Select A.ID,
2 AS [Level],
A.AccID2
From MyTable A
Where A.AccID2 IS NOT NULL
Union
Select A.ID,
3 AS [Level],
A.AccID3
From MyTable A
Where A.AccID3 IS NOT NULL
But Above query is slow and I want to have indexed view to have better performance.
and in indexed view I can't use UNION or UNPIVOT or CROSS JOIN in indexed view.
What if you created a Numbers table to essentially do the work of your illegal CROSS JOIN?
Create Table Numbers (number INT NOT NULL PRIMARY KEY)
Go
Insert Numbers
Select top 30000 row_number() over (order by (select 1)) as rn
from sys.all_objects s1 cross join sys.all_objects s2
go
Create view v_unpivot with schemabinding
as
Select MyTable.ID,
n.number as [Level],
Case n.number
When 1 Then MyTable.AccID1
When 2 Then MyTable.AccID2
Else MyTable.AccID3
End AS AccID
From dbo.Mytable
Join dbo.Numbers n on n.number BETWEEN 1 AND 3
go
Create unique clustered index pk_v_unpivot on v_unpivot (ID, [Level])
go
Select
ID,
[Level],
AccID
From v_unpivot with (noexpand)
Where AccID IS NOT NULL
Order by ID, [Level]
The WHERE AccID IS NOT NULL must be part of the query because derived tables are not allowed in indexed views.