Copy previous row value to all next rows in sql - sql-server

I have requirement to copy previous rows values to next all rows in sql server.
With LAG function, I can achieve this one only for next row. but I have to copy more than rows.
Here is sample example :

Query:
SELECT
t1.ID,
t1.CustID,
t2.ID,
t2.CustID,
t2.Flag,
COALESCE(
t2.Flag,
(
SELECT TOP 1 l.Flag
FROM TBL2 l
WHERE l.CustID = t1.CustID AND l.ID < t1.ID
ORDER BY l.ID desc
)) as 'Final'
FROM
TBL1 t1
LEFT OUTER JOIN TBL2 t2 ON t2.ID = t1.ID AND t2.CustID = t1.CustID
ORDER BY
t1.CustID,
t1.ID desc
Setup:
CREATE TABLE TBL1 (ID int, CustID int)
GO
CREATE TABLE TBL2 (ID int, CustID int, Flag bit)
GO
INSERT INTO TBL1 (ID, CustID)
SELECT 1, 11 UNION ALL
SELECT 1, 12 UNION ALL
SELECT 1, 13 UNION ALL
SELECT 1, 14 UNION ALL
SELECT 1, 15 UNION ALL
SELECT 1, 16 UNION ALL
SELECT 1, 17 UNION ALL
SELECT 2, 11 UNION ALL
SELECT 2, 12 UNION ALL
SELECT 2, 13 UNION ALL
SELECT 2, 14 UNION ALL
SELECT 2, 15 UNION ALL
SELECT 2, 16 UNION ALL
SELECT 2, 17 UNION ALL
SELECT 3, 11 UNION ALL
SELECT 3, 12 UNION ALL
SELECT 3, 13 UNION ALL
SELECT 3, 14 UNION ALL
SELECT 3, 15 UNION ALL
SELECT 3, 16 UNION ALL
SELECT 3, 17 UNION ALL
SELECT 4, 11 UNION ALL
SELECT 4, 12 UNION ALL
SELECT 4, 13 UNION ALL
SELECT 4, 14 UNION ALL
SELECT 4, 15 UNION ALL
SELECT 4, 16 UNION ALL
SELECT 4, 17
GO
INSERT INTO TBL2 (ID, CustID, Flag)
SELECT 1, 11, 0 UNION ALL
SELECT 1, 12, 1 UNION ALL
SELECT 1, 13, 1 UNION ALL
SELECT 1, 14, 0 UNION ALL
SELECT 1, 15, 0 UNION ALL
SELECT 1, 16, 0 UNION ALL
SELECT 1, 17, 1 UNION ALL
SELECT 2, 11, 1 UNION ALL
SELECT 2, 13, 0 UNION ALL
SELECT 2, 14, 1 UNION ALL
SELECT 2, 15, 1 UNION ALL
SELECT 2, 17, 0 UNION ALL
SELECT 3, 13, 1 UNION ALL
SELECT 3, 15, 0 UNION ALL
SELECT 3, 17, 1 UNION ALL
SELECT 4, 12, 0 UNION ALL
SELECT 4, 17, 0
GO

You can try this:
SELECT *
,ISNULL(b.flag,(MAX(b.flag) OVER (PARTITION BY a.[custid] ORDER BY b.[id] DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)))
FROM #TBL1 A
LEFT JOIN #TBL2 B
ON A.id = b.id
AND A.custid = b.custid
ORDER BY a.[custid] ASC, a.[id] DESC
Here is the sample data:
DECLARE #TBL1 TABLE
(
[id] TINYINT
,[custid] TINYINT
);
DECLARE #TBL2 TABLE
(
[id] TINYINT
,[custid] TINYINT
,[flag] TINYINT
);
INSERT INTO #TBL1([id], [custid])
VALUES
(1,11)
,(1,12)
,(1,13)
,(1,14)
,(1,15)
,(1,16)
,(1,17)
,(2,11)
,(2,12)
,(2,13)
,(2,14)
,(2,15)
,(2,16)
,(2,17)
,(3,11)
,(3,12)
,(3,13)
,(3,14)
,(3,15)
,(3,16)
,(3,17)
,(4,11)
,(4,12)
,(4,13)
,(4,14)
,(4,15)
,(4,16)
,(4,17);
INSERT INTO #TBL2 ([id], [custid], [flag])
VALUES (1,11,0)
,(1,12,1)
,(1,13,1)
,(1,14,0)
,(1,15,0)
,(1,16,0)
,(1,17,1)
,(2,11,1)
,(2,13,0)
,(2,14,1)
,(2,15,1)
,(2,17,0)
,(3,13,1)
,(3,15,0)
,(3,17,1)
,(4,12,0)
,(4,17,0)

You can use a LEFT JOIN ,a CASE EXPRESSION and a correlated query :
SELECT t.id,t.custid,s.id,s.custid,
COALESCE(s.flag,(SELECT TOP 1 ss.flag FROM tbl2 ss
WHERE ss.custid = t.custid and ss.id < t.id
ORDER BY ss.id DESC)) as flag
FROM Tbl1 t
LEFT JOIN tbl2 s
ON(t.custid = s.custid and s.id = t.id)

Related

SQL replace null with list of values

I have a City and StatePopulation tables
CREATE TABLE dbo.City
(
Code INT,
CityName VARCHAR(30)
)
INSERT INTO CITY (CODE, CityName)
select 1, 'Woodside'
union
select 2, 'Sunnyside'
union
select 3, 'Flushing'
union
select 4, 'Elmhurst'
union
select 5, 'ForestHills'
union
select 6, 'Manhattan'
union
select 7, 'Atlanta'
union
select 8, 'Alpharetta'
union
select 9, 'Johns Creek'
CREATE TABLE DBO.CityPopulation
(
StateCode VARCHAR(10),
CityCode INT,
PopulationCount INT
)
INSERT INTO DBO.CityPopulation (StateCode, CityCode, PopulationCount)
SELECT 'NY', 1, 1000
UNION
SELECT 'NY', 2, 1500
UNION
SELECT 'NY', 3, 2500
UNION
SELECT 'NY', 4, 3000
UNION
SELECT 'NY', 5, 3500
UNION
SELECT 'NY', 6, 4000
UNION
SELECT 'GA', 7, 5500
UNION
SELECT 'GA', 8, 1200
UNION
SELECT 'GA', 9, 1900
CREATE TYPE dbo.UDTT_StateType AS TABLE (StateCode VARCHAR(10), CityCode INT)
DECLAR #State dbo.UDTT_StateType
INSERT INTO #State (StateCode, CityCode)
select 'NY', null
union
select 'GA', 8
Now I need to return the rows from CityPopulation for the values in the UDTT_StateType that are matching on the StateCode and CityCode, but when the StateCode is 'NY' and the City Code is null, I need to return data for CityCode 1 and 2
Can anyone help me to write this query, please?
you can try this;
select c.* from CityPopulation c,#State s where
s.CityCode is null
And c.CityCode in (1,2,3,4,5,6)
And c.StateCode = s.StateCode
Union
select c.* from CityPopulation c,#State s where
c.CityCode =s.CityCode
And c.StateCode = s.StateCode
I was able to solve this with a CROSS JOIN.
SELECT cpd.StateCode, cpd.CityCode, cpd.CityName, cpd.PopulationCount
FROM #State AS s
CROSS JOIN (SELECT * FROM CityPopulation AS cp INNER JOIN city AS c ON cp.CityCode = c.Code
WHERE CityCode IN (1,2)) AS cpd
WHERE s.CityCode = cpd.CityCode OR s.CityCode IS NULL
Which produced the following result:
select c.*
from CityPopulation c, State s
where (
(c.StateCode = s.StateCode and c.CityCode = s.CityCode)
OR (s.StateCode = 'NY' and s.CityCode is null and (c.StateCode='NY' and c.CityCode in (1,2)))
)

Multiple Parent Child trees in one table. Select down each tree from a node value

I have a table containing three trees:
T1 T2 T3 T4
-- -- -- --
A F B H
| | | | | | |
B C B C A C I
| | | |
D E D B
| |
G J
I'd like to be able to get the distinct nodes sitting under a specific node value.
So for B that'd be D, E, G, D, A, C and J where the distinct is A, C, D, E, G, J
declare #t table (t_id int, parent_t_id int, tree varchar(2), item varchar)
insert into #t
select 1, 0, 'T1', 'A' union
select 2, 1, 'T1', 'B' union
select 3, 1, 'T1', 'C' union
select 4, 2, 'T1', 'D' union
select 5, 2, 'T1', 'E' union
select 5, 4, 'T1', 'G' union
select 6, 0, 'T2', 'F' union
select 7, 6, 'T2', 'B' union
select 8, 6, 'T2', 'C' union
select 9, 7, 'T2', 'D' union
select 10, 0, 'T3', 'B' union
select 11, 10, 'T3', 'A' union
select 12, 10, 'T3', 'C' union
select 13, 0, 'T4', 'H' union
select 14, 13, 'T4', 'I' union
select 15, 14, 'T4', 'B' union
select 16, 15, 'T4', 'J'
select * from #t
I suspect a CTE is required?
try this:
;with cte as
(
Select t1.* From #t t1
JOIN #t t2 on t1.parent_t_id=t2.t_id AND t1.tree=t2.tree
Where t2.item =#Item
Union All
Select t1.* From #t t1
JOIN cte t2 on t1.parent_t_id=t2.t_id AND t1.tree=t2.tree
)
Select DISTINCT Item FROM cte
Yes, CTE can be an option
SELECT * FROM #t ORDER BY t_id
;WITH myCTE (Id, ParentId,Item)
AS
(SELECT t_Id ,Parent_t_Id ,Item
FROM #t
UNION ALL
SELECT t_Id ,Parent_t_Id ,t1.Item
FROM #t t1
INNER JOIN myCTE tmp ON tmp.ParentId = t1.t_Id
)
SELECT DISTINCT * FROM myCTE ORDER BY parentId

PIVOT and several aggregates in sql server 2014

My current understanding is that it is impossible to have several aggregates - such as an additional SUM(Measure2) in the following example:
IF OBJECT_ID('tempdb..#Dim1') IS NOT NULL DROP TABLE #Dim1
IF OBJECT_ID('tempdb..#Dim2') IS NOT NULL DROP TABLE #Dim2
IF OBJECT_ID('tempdb..#Facts') IS NOT NULL DROP TABLE #Facts
CREATE TABLE #Dim1
(
Id INT IDENTITY(1,1),
DimName NVARCHAR(100)
)
CREATE TABLE #Dim2
(
Id INT IDENTITY(1,1),
DimName NVARCHAR(100)
)
CREATE TABLE #Facts
(
Id INT IDENTITY(1,1),
Dim1Id INT,
Dim2Id INT,
Measure1 FLOAT,
Measure2 FLOAT
)
INSERT INTO #Dim1
SELECT N'Dim1Name1'
UNION ALL
SELECT N'Dim1Name2'
UNION ALL
SELECT N'Dim1Name3'
INSERT INTO #Dim2
SELECT N'Dim2Name1'
UNION ALL
SELECT N'Dim2Name2'
INSERT INTO #Facts
SELECT 1, 2, 2, 10
UNION ALL
SELECT 1, 2, 10, 3
UNION ALL
SELECT 1, 1, 1, 56
UNION ALL
SELECT 2, 1, 5, 4
UNION ALL
SELECT 2, 2, 4, 4
UNION ALL
SELECT 3, 1, 4, 1
UNION ALL
SELECT 3, 1, 20, 56
;WITH CTE1 AS
(
SELECT
Facts.Measure1,
Dimensions1.DimName AS DimName1,
Dimensions2.DimName AS DimName2
FROM #Facts AS Facts
INNER JOIN #Dim1 AS Dimensions1 ON Facts.Dim1Id = Dimensions1.Id
INNER JOIN #Dim2 AS Dimensions2 ON Facts.Dim2Id = Dimensions2.Id
)
SELECT
*
FROM CTE1
PIVOT
(
SUM(Measure1)
FOR DimName2
IN([Dim2Name1], [Dim2Name2])
) AS X;
Is this really the case and do I have to use the old 'MAX CASE' approach for these scenarios?
Is this helpful?
;WITH CTE1 AS
(
SELECT
Facts.Measure1,
Facts.Measure2,
Dimensions1.DimName AS DimName1,
Dimensions2.DimName AS DimName2
FROM #Facts AS Facts
INNER JOIN #Dim1 AS Dimensions1 ON Facts.Dim1Id = Dimensions1.Id
INNER JOIN #Dim2 AS Dimensions2 ON Facts.Dim2Id = Dimensions2.Id
)
SELECT
DimName1,
CAST(SUBSTRING(X.[Dim2Name1], 1, 10) AS INT) Dim2Name1Measure1,
CAST(SUBSTRING(X.[Dim2Name1], 11, 10) AS INT) Dim2Name1Measure2,
CAST(SUBSTRING(X.[Dim2Name2], 1, 10) AS INT) Dim2Name2Measure1,
CAST(SUBSTRING(X.[Dim2Name2], 11, 10) AS INT) Dim2Name2Measure2
FROM
(
SELECT
CAST(SUM(Measure1) AS CHAR(10)) + CAST(SUM(Measure2) AS CHAR(10)) AS Combined,
DimName1,
DimName2
FROM CTE1
GROUP BY
DimName1,
DimName2
) S
PIVOT
(
MAX(Combined)
FOR DimName2
IN([Dim2Name1], [Dim2Name2])
) AS X;

How to use pivot in this table

Actual Table Structure
===================================
slno ParnetID ParnetName Promotion Marketer
1 SLM1010S SKR.RAJASHEGARAN 2 43640
2 40049 M.KANNAN 3 43640
3 40018 M.PRABU 6 43640
4 SLM1010S SKR.RAJASHEGARAN 2 43641
5 40042 M.KANNAN 3 43641
6 40011 M.PRABU 6 43641
i have my query :
WITH temp
AS (SELECT slno,
parentid,
parentname,
parentpromotionid,
marketerid,
(SELECT Count(*)
FROM parentmaster
WHERE t1.marketerid = marketerid
AND t1.parentid = parentid
AND t1.parentname = parentname
AND slno <= t1.slno) AS RowNum
FROM parentmaster AS t1)
SELECT marketerid,
[2],
[6],
[3]
FROM temp
PIVOT ( Min(parentid)
FOR parentpromotionid IN ([2],
[6],
[3]) ) AS t
But I want This Table Structure
MarketerID 2 6 3
43640 SLM1010S 40018 40049
43641 SLM1010S 40011 40042
This may help u..
select marketer,[2],[3],[6] from
(
select Marketer,Promotion,ParnetID
from parentmaster
) d pivot (min(ParnetID) for Promotion in ([2],[3],[6])) as pvt
try this,
Declare #t table(slno int,ParnetID varchar(50),ParnetName varchar(50),Promotion int,Marketer int)
insert into #t
select 1,'SLM1010S','SKR.RAJASHEGARAN', 2, 43640 union all
select 2,'40049','M.KANNAN', 3, 43640 union all
select 3,'40018', 'M.PRABU', 6, 43640 union all
select 4,'SLM1010S', 'SKR.RAJASHEGARAN', 2, 43641 union all
select 5,'40042', 'M.KANNAN', 3, 43641 union all
select 6,'40011', 'M.PRABU', 6, 43641
select distinct a.Marketer,b.ParnetID ,c.ParnetID,d.ParnetID from #t a
left join #t b on a.Marketer=b.Marketer and b.promotion=2
left join #t c on a.Marketer=c.Marketer and c.promotion=3
left join #t d on a.Marketer=d.Marketer and d.promotion=6
select Marketer, [0],[1],[2],[3],[4],[5],[6]
from (
select Marketer,Promotion,ParnetID
from #t
) d
pivot
(
MIN(ParnetID)
FOR Promotion
IN ([0],[1],[2],[3],[4],[5],[6])
) as TST

Update a special id in hierarchical employee table

I have an update that has to be made. And Im really stuck.
This is a classic hierarchical employee table question, but with a twist.
Please look at this tree of users:
employees
(Completely unrelated to my problem, just something I found with google pictures)
Lets assume the following Id's:
RM1: EmpId 1, ParentId null
AM1: EmpId 2, ParentId 1
MGR1: EmpId 3, ParentId 2
MGR2: EmpId 4, ParentId 2
EMP1: EmpId 5, ParentId 3
EMP2: EmpId 6, ParentId 3
EMP3: EmpId 7, ParentId 4
EMP4: EmpId 8, ParentId 4
I need to add another column, lets call it parentSpecialId.
This id is the id of the user below root (AM1 and AM2).
All users below AM1 and AM2 should have the parentSpecialId set to the user below root.
Which gives us:
RM1: EmpId 1, ParentId null parentSpecialId null
AM1: EmpId 2, ParentId 1 parentSpecialId null
MGR1: EmpId 3, ParentId 2 parentSpecialId 2
MGR2: EmpId 4, ParentId 2 parentSpecialId 2
EMP1: EmpId 5, ParentId 3 parentSpecialId 2
EMP2: EmpId 6, ParentId 3 parentSpecialId 2
EMP3: EmpId 7, ParentId 4 parentSpecialId 2
EMP4: EmpId 8, ParentId 4 parentSpecialId 2
All I have is this CTE which gives me a result set with AM1 and AM2.
So I need to traverse all way down to EMPX and update parentSpecialId with Id 2 for
AM1 and the same for all users for AM2. Of course, it needs to by dynamic, in real life I have 12 of these users below root.
Does it make sense?
Here is my CTE:
WITH EmpsCTE AS
(
SELECT id, parent, name, 0 AS EmployeeLevel
FROM Employee
WHERE parent = 0
UNION ALL
SELECT e.id, e.parent, e.name, EmployeeLevel + 1
FROM EmpsCTE AS p
JOIN Employee AS e ON e.parent = p.id
)
SELECT id, parent, name, EmployeeLevel
From EmpsCTE where EmployeeLevel = 1
Oh, and I use Sql server 2008 R2
Sample data:
declare #T table
(
Name varchar(10),
EmpId int,
ParentId int,
ParentSpecialID int
);
insert into #T(Name, EmpId, ParentId) values
('RM1', 1, null),
('AM1', 2, 1),
('MGR1', 3, 2),
('MGR2', 4, 2),
('EMP1', 5, 3),
('EMP2', 6, 3),
('EMP3', 7, 4),
('EMP4', 8, 4);
Update statement:
with C as
(
select T3.EmpId,
T2.EmpId as ParentSpecialId
from #T as T1
inner join #T as T2
on T1.EmpId = T2.ParentId
inner join #T as T3
on T2.EmpId = T3.ParentId
where T1.ParentId is null
union all
select T.EmpId,
C.ParentSpecialId
from #T as T
inner join C
on T.ParentId = C.EmpId
)
update T
set ParentSpecialId = C.ParentSpecialId
from #T as T
inner join C
on T.EmpId = C.EmpId
To handle a tree of arbitrary depth:
declare #T table ( Name varchar(16), EmpId int, ParentId int );
insert into #T(Name, EmpId, ParentId) values
('RM1', 1, null),
('AM1', 2, 1),
('MGR1', 3, 2),
('MGR2', 4, 2),
('EMP1', 5, 3),
('EMP2', 6, 3),
('EMP3', 7, 4),
('EMP4', 8, 4),
('AM2', 9, 1),
('MGR3', 10, 9),
('EMP5', 11, 10),
('Brown Noser', 12, 11),
('Intern', 13, 12),
('Coop', 14, 13),
('Nephew', 15, 14),
('Contractor', 16, 15);
; with CTE as (
-- Start with the root(s).
select Name, EmpId, ParentId, 0 as Depth, Cast(NULL as Int) as parentSpecialId
from #T
where ParentId is NULL
union all
-- Add the direct reports one layer at a time.
select T.Name, T.EmpId, T.ParentId, CTE.Depth + 1, case when CTE.Depth = 1 then T.ParentId else CTE.parentSpecialId end
from CTE inner join
#T as T on T.ParentId = CTE.EmpID
where T.ParentId = CTE.EmpId
)
select *,
( select Name from CTE as R where R.EmpId = CTE.ParentId ) as ReportsTo,
( select Name from CTE as SC where SC.EmpId = CTE.parentSpecialId ) as SubCommander
from CTE
order by Depth, Name
With thanks to Mikael Eriksson for setting up the sample data!

Resources