Summation of the Grand total - sql-server

I have the below requirement
As can be figure out that for every Collector whenever the SubProduct is changing, we are performing it's "SubTotal".
Once the "SubTotal" is over, then we are performing the "Product Total" which is the summation of the "SubProducts" for that collector at the Product level (means until the Product is changed).
and finally, "Grand Total" of that Collector's Product
e.g.
Collector Amreet has 2 Products (NCB and NCT). For NCB he has 2 subProducts viz. Credit Card and Loan. His Product Total is computed at both NCB and NCT level and Grand Total for all the products.
Same is the case for the collector "Vijay"
I have written the below code which is very close to the requirement only thing is that, I'm not able to Add/append Collector Name at the Grand Total Level.
My attempt so far
declare #t table(Collector varchar(50),Product varchar(50),SubProduct varchar(50),Amount int)
Insert into #t
select 'Vijay','NCB','Credit Card',8000 union all
select 'Vijay','NCB','Credit Card',2000 union all
select 'Vijay','NCB','Credit Card',17000 union all
select 'Vijay','NCB','Credit Card',5000 union all
select 'Vijay','NCB','Loan',15000 union all
select 'Vijay','NCB','Loan',5000 union all
select 'Amreet','NCB','Credit Card',3000 union all
select 'Amreet','NCB','Credit Card',1000 union all
select 'Amreet','NCB','Loan',45000 union all
select 'Amreet','NCB','Loan',9000 union all
select 'Amreet','NCT','Loan',1000 union all
select 'Amreet','NCT','Loan',2000
Select
*
from
(select
case when grouping(Rn) = 1 then '' else Collector end as Collector,
case when grouping(Rn) = 1 then '' else Product end as Product,
case
when grouping(Collector) = 0 and grouping(Product) = 1 and grouping(SubProduct) = 1 and grouping(Rn) = 1 then 'Grand Total'
when grouping(Collector) = 0 and grouping(Product) = 0 and grouping(SubProduct) = 1 and grouping(Rn) = 1 then 'Total(Product Total)'
when grouping(Collector) = 0 and grouping(Product) = 0 and grouping(SubProduct) = 0 and grouping(Rn) = 1 then 'SubTotal(Sub Product Total)'
else SubProduct end as SubProduct,
sum(Amount) as Amount
from
(select
*,
Rn = row_number() over(partition by Collector,Product,SubProduct order by 1/0)
from #t) tData
group by
rollup(Collector,Product,SubProduct, Rn))x
where x.SubProduct is not null
Output

Please check this one. Here I've added in one things.
declare #t table(Collector varchar(50),Product varchar(50),SubProduct varchar(50),Amount int)
Insert into #t
select 'Vijay','NCB','Credit Card',8000 union all
select 'Vijay','NCB','Credit Card',2000 union all
select 'Vijay','NCB','Credit Card',17000 union all
select 'Vijay','NCB','Credit Card',5000 union all
select 'Vijay','NCB','Loan',15000 union all
select 'Vijay','NCB','Loan',5000 union all
select 'Amreet','NCB','Credit Card',3000 union all
select 'Amreet','NCB','Credit Card',1000 union all
select 'Amreet','NCB','Loan',45000 union all
select 'Amreet','NCB','Loan',9000 union all
select 'Amreet','NCT','Loan',1000 union all
select 'Amreet','NCT','Loan',2000
Select
*
from
(select
case when grouping(Rn) = 1 then '' else Collector end as Collector,
case when grouping(Rn) = 1 then '' else Product end as Product,
case
when grouping(Collector) = 0 and grouping(Product) = 1 and grouping(SubProduct) = 1 and grouping(Rn) = 1 then 'Grand Total (' + Collector + ')'
when grouping(Collector) = 0 and grouping(Product) = 0 and grouping(SubProduct) = 1 and grouping(Rn) = 1 then 'Total(Product Total)'
when grouping(Collector) = 0 and grouping(Product) = 0 and grouping(SubProduct) = 0 and grouping(Rn) = 1 then 'SubTotal(Sub Product Total)'
else SubProduct end as SubProduct,
sum(Amount) as Amount
from
(select
*,
Rn = row_number() over(partition by Collector,Product,SubProduct order by 1/0)
from #t) tData
group by
ROLLUP(Collector,Product,SubProduct, Rn))x
where x.SubProduct is not null;

Related

Combine results of two queries with the same value into one row

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;

Eliminate similar cycles in directed graph

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.

Stored procedure code works to insert data into table but does not work when called from the stored procedure node

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

Create new columns depending on the columns in a table

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

join multiple queries result in to seperate columns

hello everyone i have 3 queries it gives when i used union All its give me 3 rows i want to convert 3 rows into columns how can i do that please help me
here is my query
( select count(*) As TotalCount from Detail_User
where userkey = 172 )
--union
( select count(*) As ICount1 from Detail_User
where Parent_Name = 'A' and userkey = 172 )
--union
( select count(*) As ICount2 from Detail_User
where Parent_Name = 'B' and userkey = 172 )
its give me some thing like this
TotalCount
2
3
5
i want something like this
TotalCount ICount1 ICount2
2 3 5
Don't do a UNION, use a CASE WHEN in your SELECT like this
select
count(*) As TotalCount,
SUM(CASE WHEN Parent_Name = 'A' THEN 1 ELSE 0 END) as ICount1 ,
SUM(CASE WHEN Parent_Name = 'B' THEN 1 ELSE 0 END) as ICount2
from Detail_User
where userkey = 172

Resources