Here is my query:
select fldUserId, count(*) AS TOTAL
from tblWorkHistory
where fldStatus = '1'
group by fldUserId
union
select fldEmpID, count(*) AS TOTAL
from tblQAHistory
where fldStatus = '1'
group by fldEmpID
Output:
fldUserId TOTAL
16070004 34
19100015 1
19100015 7
191014571 3
I want to combine both rows with '19100015' into one row.
Use your query as a sub-query:
with cte as (
select fldUserId, count(*) as TOTAL
from tblWorkHistory
where fldStatus = '1'
group by fldUserId
union
select fldEmpID, count(*)
from tblQAHistory
where fldStatus = '1'
group by fldEmpID
)
select fldUserId, sum(TOTAL) as TOTAL
from cte
group by fldUserId
An alternative is to group just once on the outside
select
t.fldUserId,
count(*) as TOTAL
from (
select fldUserId
from tblWorkHistory
where fldStatus = '1'
union all
select fldEmpID
from tblQAHistory
where fldStatus = '1'
) t
group by
t.fldUserId;
I have the following data:
Table:
CREATE TABLE tblLoop
(
person1 varchar(20),
person2 varchar(20),
ColDate date,
);
INSERT INTO tblLoop VALUES('A','B','2020-01-01'),('A','C','2020-01-01'),('A','D','2020-01-01'),
('B','E','2020-01-02'),('B','F','2020-01-02'),
('D','G','2020-01-03'),('D','H','2020-01-03'),
('F','i','2020-01-04'),
('G','J','2020-01-05'),
('i','A','2020-01-06'),
('J','D','2020-01-07'),
('X','Y','2020-01-08'),('X','Z','2020-01-08'),
('Z','X','2020-01-09'),
('Y','W','2020-01-09');
Records Look like:
Requirement: I need to find the persons which forms a cycle. For an example in the given data we found 3 Cycle's:
Cycle 1: A connected with B connected with F connected with i connected with A.
Cycle 2: A connected with D connected with G connected with J connected with D.
Cycle 3: X connected with Z connected with X.
Expected result:
LoopFound
--------------------
A->B->F->i->A
A->D->G->J->D
X->Z->X
My try:
;WITH CTE AS
(
SELECT Person1, Person2,
CONVERT(VARCHAR(MAX), (','+ Person1+ ','+ Person2+ ',')) AS nodes, 1 AS lev,
(CASE WHEN Person1 = Person2 THEN 1 ELSE 0 END) AS has_cycle
FROM tblLoop e
UNION ALL
SELECT cte.Person1, e.Person2,
CONVERT(VARCHAR(MAX), (cte.nodes+ e.Person2+ ',')), lev + 1,
(CASE WHEN cte.nodes LIKE ('%,'+ e.Person2+ ',%') THEN 1 ELSE 0 END) AS has_cycle
FROM CTE
JOIN tblLoop e ON e.Person1 = cte.Person2
WHERE cte.has_cycle = 0
)
SELECT *
FROM CTE
WHERE has_cycle = 1;
NOTE: Getting multiple combination of cycles from above query.
As per the comment by Kevin, the answer lies in including a flag to indicate that a given node is a valid start point, and can be included in the query:
In this instance, 'A' and 'X' are given as start points, therefore we will mark all records where the originator is either 'A' or 'X':
CREATE TABLE #tblLoop
(
person1 varchar(20),
person2 varchar(20),
ColDate date,
isRoot INT
);
INSERT INTO #tblLoop VALUES('A','B','2020-01-01',1),
('A','C','2020-01-01',1),
('A','D','2020-01-01',1),
('B','E','2020-01-02',0),
('B','F','2020-01-02',0),
('D','G','2020-01-03',0),
('D','H','2020-01-03',0),
('F','i','2020-01-04',0),
('G','J','2020-01-05',0),
('i','A','2020-01-06',0),
('J','D','2020-01-07',0),
('X','Y','2020-01-08',1),
('X','Z','2020-01-08',1),
('Z','X','2020-01-09',0),
('Y','W','2020-01-09',0);
Then the following query can be amended as follows:
;WITH CTE AS
(
SELECT Person1, Person2, isRoot,
CONVERT(VARCHAR(MAX), (','+ Person1+ ','+ Person2+ ',')) AS nodes, 1 AS lev,
(CASE WHEN Person1 = Person2 THEN 1 ELSE 0 END) AS has_cycle
FROM #tblLoop e
UNION ALL
SELECT cte.Person1, e.Person2, cte.isRoot,
CONVERT(VARCHAR(MAX), (cte.nodes+ e.Person2+ ',')), lev + 1,
(CASE WHEN cte.nodes LIKE ('%,'+ e.Person2+ ',%') THEN 1 ELSE 0 END) AS has_cycle
FROM CTE
JOIN #tblLoop e ON e.Person1 = cte.Person2
WHERE cte.has_cycle = 0
)
SELECT *
FROM CTE
WHERE has_cycle = 1
AND isRoot = 1
Credit to Kevin for the idea, this is just a working implementation of it.
I have tried the following two steps:
Step 1: In this step, Find the start node's of the graph.
--Create table to store start nodes
IF OBJECT_ID('dbo.Temp_tblLoop', 'U') IS NOT NULL
BEGIN
DROP TABLE dbo.Temp_tblLoop;
END
--Query to find start nodes.
;WITH CTE AS
(
SELECT t.*
FROM tblLoop t
WHERE person1 IN (SELECT person2 FROM tblLoop t2 WHERE t.ColDate<= t2.ColDate) OR
person2 IN (SELECT person1 FROM tblLoop t3 WHERE t.ColDate<= t3.ColDate)
)
SELECT DISTINCT person1 INTO Temp_tblLoop
FROM CTE
WHERE person1 NOT IN (SELECT person2 FROM CTE);
Step 2: Find out the cycles in the graph (Excluding Similar Cycles)
;WITH CTE AS
(
SELECT Person1, Person2,
CONVERT(VARCHAR(MAX), (Person1+ '->'+ Person2)) AS nodes, 1 AS lev,
(CASE WHEN Person1 = Person2 THEN 1 ELSE 0 END) AS has_cycle
FROM tblLoop e WHERE person1 IN (SELECT person1 FROM Temp_tblLoop)
UNION ALL
SELECT cte.Person1, e.Person2,
CONVERT(VARCHAR(MAX), (cte.nodes+'->'+ e.Person2)), lev + 1,
(CASE WHEN CHARINDEX(e.Person2, cte.nodes) != 0 THEN 1 ELSE 0 END) AS has_cycle
FROM CTE
JOIN tblLoop e ON e.Person1 = cte.Person2
WHERE cte.has_cycle = 0
)
SELECT Person1 AS Start, Person2 AS [End],
nodes AS Links,
lev AS Levels
FROM CTE
WHERE has_cycle = 1;
Let me your reviews, if anything needs to be done for betterment.
Here is the full stored procedure. When I select everything between "set no count on" and "end" it works perfectly and table zLOC_invValue gets updated with 2 lines.
If I try to right click on the stored procedure node and choose to execute, the return value is 0 and the table is not updated. I also get the message that the query is executed successfully.
USE [TWL_PROD]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Update_invValue]
AS
BEGIN
SET NOCOUNT ON;
select 'S ' + whse as whse, prod, qtyonhand + qtyunavail as qty ,(avgcost+addoncost) as cost into #stock from openquery ( twllive, 'select whse, prod, qtyonhand,qtyunavail,avgcost,addoncost from pub.icsw where cono = ''1'' and whse in (''mtl'', ''nob'', ''tdc'', ''oak'')');
select 'NS ' + whse as whse, prod, sum(quantity) as qty, sum( case when quantity > 0 then amount else -1*amount end) as total_value into #nStock from openquery ( twllive, 'select b.* from pub.icenh a left join pub.icenl b on a.cono = b.cono and a.typecd = b.typecd and a.whse = b.whse and a.prod = b.prod and a.prodcat = b.prodcat and a.seqnoh = b.seqnoh where a.cono = ''1'' and a.typecd = ''n'' and a.whse in (''mtl'', ''tdc'', ''nob'', ''oak'') and a.activefl = 1 ')
group by whse, prod;
select co_num , abs_num as prod, bin_num, total_qty,total_qty * 1.00 as value, item_type into #3pl from openquery (twllive, 'select a.co_num, a.abs_num, a.total_qty, a.bin_num, b.item_type from pub.inventory a left join pub.item b on a.wh_num = b.wh_num and a.abs_num = b.abs_num where a.co_num = ''1'' and a.wh_num = ''mtl'' and bin_num in ( ''dockexpp'', ''dockexca'', ''docktransi'')');
update #3PL set Value = (g.total_value/g.qty) * a.total_qty from #3PL a inner join #nStock g on a.prod = g.prod where A.item_type = 'n' and g.whse = 'NS mtl';
update #3PL set Value = (g.cost) * a.total_qty from #3PL a inner join #Stock g on a.prod = g.prod where A.item_type = 's' and g.whse = 's mtl' ;
select co_num, SUM(case when bin_num = 'dockexpp' and item_type = 's' then value else 0 end) as Stock_Plaspak,SUM(case when bin_num = 'dockexpp' and item_type = 'n' then value else 0 end) as NS_Plaspak , SUM(case when bin_num = 'dockexca' and item_type = 's' then value else 0 end) as Stock_Caratrans , SUM(case when bin_num = 'dockexca' and item_type = 'N' then value else 0 end) as NS_Caratrans, SUM(case when bin_num = 'docktransi' and item_type = 's' then value else 0 end) as Stock_Transit,SUM(case when bin_num = 'docktransi' and item_type = 'n' then value else 0 end) as NS_transit into #3PL1 from #3PL group by co_num;
select * into #temp from (
select 1 as cono, whse, SUM(total_value) as value from #nStock group by whse
union all
select 1 as cono, whse, SUM(qty * cost) as value from #Stock group by whse
union all
select 1 as cono,'S-3PL' as whse, SUM(case when item_type = 's' then value else 0 end) as value from #3pl
union all
select 1 as cono,'NS-3PL' as whse, SUM(case when item_type = 'n' then value else 0 end)as value from #3pl ) "a";
update #temp set value = ((select value from #temp where whse = 'ns mtl') - (select value from #temp where whse = 'ns-3pl') ) where whse = 'ns mtl';
update #temp set value = ((select value from #temp where whse = 's mtl') - (select value from #temp where whse = 's-3pl') ) where whse = 's mtl';
select cono,[NS MTL],[NS NOB],[NS OAK],[NS TDC],[S MTL],[S NOB], [S OAK], [S TDC] into #stock1 from #temp
pivot (max(value) for whse in ([NS MTL],[NS NOB],[NS OAK],[NS TDC],[S MTL],[S NOB], [S OAK], [S TDC])) as PivotTable;
insert into zloc_InvValue select * from (
select 'Stock: ' as [type], GETDATE() as [date], a.[S MTL] as MTL,a.[S NOB] as NOB, a.[S OAK] as OAK, a.[S TDC] as TDC, b.Stock_Plaspak as [3PL- Plaspak], b.Stock_Caratrans as [3PL- Caratrans], b.Stock_transit as [3PL- transit] from #stock1 a full outer join #3PL1 b on a.cono = b.co_num
union all
select 'Non-Stock: ' , GETDATE() , a.[NS MTL],a.[NS NOB], a.[NS OAK], a.[NS TDC], b.NS_Plaspak, b.NS_Caratrans, b.NS_transit from #stock1 a full outer join #3PL1 b on a.cono = b.co_num ) "a"
drop table #nStock
drop table #stock
drop table #3PL
drop table #3PL1
drop table #temp
drop table #stock1
END
I have code in the this following example.
legacy_id phone_type phone_number
1 f 1234567890
1 b 1233854100
1 f 4110256565
2 f 0707070770
2 b 7895120044
I want the data to end up like the following.
legacy_id f_phone_number_1 b_phone_number_1 f_phone_number_2
1 1234567890 1233854100 4110256565
2 0707070770 7895120044
My initial approach works but I was hoping there is a more efficient what of doing this.
Select fill.legacy_id, max(fill.f_phone_number_1),max(fill.b_phone_number_1),max(fill.f_phone_number_2)
from
(
Select
a.legacy_id as legacy_id, a.phone_type as phone_type,
case
when a.phone_type = 'F' then a.phone_number and
dense_rank() over (partition by a.legacy_id, a.phone_type order by a.legacy_id, a.phone_type, a.phone_number) = 1
else null
end as f_phone_number_1,
case
when a.phone_type = 'F' then a.phone_number and
dense_rank() over (partition by a.legacy_id, a.phone_type order by a.legacy_id, a.phone_type, a.phone_number) = 2
else null
end as f_phone_number_2,
case
when a.phone_type = 'b' then a.phone_number and
dense_rank() over (partition by a.legacy_id, a.phone_type order by a.legacy_id, a.phone_type, a.phone_number) = 1
else null
end as b_phone_number_1
from table a
group by a.legacy_id, a.phone_type, a.phone_number
) fill
group by fill.legacy_id
Is there a more efficient way of approaching this?
If you don't need to go dynamic, a conditional aggregation should do the trick
Declare #YourTable table (legacy_id int,phone_type varchar(25),phone_number varchar(25))
Insert Into #YourTable values
(1,'f','1234567890'),
(1,'b','1233854100'),
(1,'f','4110256565'),
(2,'f','0707070770'),
(2,'b','7895120044')
Select legacy_id
,f_phone_number_1 = max(case when phone_type='f' and RowNr=1 Then phone_number else '' end)
,b_phone_number_1 = max(case when phone_type='b' and RowNr=1 Then phone_number else '' end)
,f_phone_number_2 = max(case when phone_type='f' and RowNr=2 Then phone_number else '' end)
,b_phone_number_2 = max(case when phone_type='b' and RowNr=2 Then phone_number else '' end)
From (
Select *
,RowNr=Row_Number() over (Partition By legacy_id,phone_type Order By (Select NULL) )
From #YourTable
) A
Group By legacy_id
Returns
legacy_id f_phone_number_1 b_phone_number_1 f_phone_number_2 b_phone_number_2
1 4110256565 1233854100 1234567890
2 0707070770 7895120044