SQL Query-Group by and filters - sql

I have the table as shown in below image.
I am trying to get the latest status_id, grouped by team_id and based on max of created_date.
--Latest status for each team based on created date
SELECT *
FROM ProductionHistory
WHERE created_Date IN (
SELECT MAX(created_Date)
FROM ProductionHistory
GROUP BY TeamID
)
That's fine, here is the result:
My questions are:
How to ignore the assigned_to null then find latest record for team?
When there is only one record with assigned_to null for team, let's consider that.
For example: for Team_id 5 there is only one record with assigned_to null, we don't have any other record for team_id 5 with assigned_to set some value.
So we have consider this.
For team id 3 query result should ignore the record 4 (though max date), query result should contain record 2.
Here is the final result I am expecting:

Try this:
DECLARE #t TABLE
(
TicketID INT ,
TeamID INT ,
StatusID INT ,
created_Date DATETIME ,
Assigned_to NVARCHAR(MAX)
)
INSERT #t
VALUES ( 10000, 2, 7, '2015-03-26 01:48:00.000', 'W3ER45' ),
( 10000, 3, 7, '2015-03-26 05:48:00.000', 'YU67IO' ),
( 10000, 2, 9, '2015-03-26 03:48:00.000', 'HJKO98' ),
( 10000, 3, 9, '2015-03-27 03:48:00.000', NULL ),
( 10000, 4, 11, '2015-03-23 03:48:00.000', 'GHR67' ),
( 10000, 5, 11, '2015-03-27 02:12:56.910', NULL );
;
WITH cte
AS ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY TicketID, TeamID ORDER BY CASE
WHEN Assigned_to IS NULL
THEN 1
ELSE 0
END, created_Date DESC ) AS rn
FROM #t
)
SELECT TicketID ,
TeamID ,
StatusID ,
created_Date ,
Assigned_to
FROM cte
WHERE rn = 1
Output:
TicketID TeamID StatusID created_Date Assigned_to
10000 2 9 2015-03-26 03:48:00.000 HJKO98
10000 3 7 2015-03-26 05:48:00.000 YU67IO
10000 4 11 2015-03-23 03:48:00.000 GHR67
10000 5 11 2015-03-27 02:12:56.910 NULL

Try this answer.I did it with cursor
DECLARE #t TABLE ( TicketID INT
, TeamID INT
, StatusID INT
, created_Date DATETIME
, Assigned_to NVARCHAR(MAX) )
DECLARE cur CURSOR READ_ONLY FAST_FORWARD
FOR SELECT [TeamID]
FROM TT
DECLARE #i int
OPEN cur
FETCH NEXT FROM cur INTO #i
WHILE ##FETCH_STATUS=0
BEGIN
IF (SELECT COUNT_BIG([TeamID])
FROM TT
WHERE [TeamID]=#i)>1
BEGIN
INSERT INTO #T
SELECT TOP 1 *
FROM [dbo].[TT]
WHERE [TeamID]=#i AND [Assigned_to] IS NOT NULL
ORDER BY [created_Date] DESC
END
ELSE
BEGIN
INSERT INTO #T
SELECT *
FROM [dbo].[TT]
WHERE [TeamID]=#i
END
FETCH NEXT FROM cur INTO #i
END
SELECT TicketID
, TeamID
, StatusID
, Assigned_to
, created_Date
FROM #T
GROUP BY TicketID
, TeamID
, StatusID
, created_Date
, Assigned_to
CLOSE cur
DEALLOCATE cur

Related

Set a Group number when cumulative column less than or equal to target

I have a column which contains how many sub_links a website has.
My table schema is id, sub_link, link
id sub_link link group
1 5 link1.com 1
2 2 link2.com 2
3 4 link3.com 3
4 1 link4.com 3
4 1 link4.com 3
5 2 link5.com 4
6 4 link6.com 5
7 3 link7.com 6
7 3 link7.com 6
I want to add a column with group number when the total of sub_link is equal or less than 5 along with avoiding duplicates.
I don't know where to start since I can only write select statements and make some joins.
Maybe there is a way using Window Function or CTE which I prefer to further my experience.
Here is a fiddle link
https://www.db-fiddle.com/f/6rmtcazWaWvLULZ5QgpmSb/1
Thank you for your help.
Based on your comment below, I'm not sure how to do this outside of keeping track of the rolling Sub_link sum in a separate temp table. An example of this below. IF you only needed to keep track of the Sub_links for current record and previous, may be way to accomplish with single query utilizing LAG function.
USE [master]
GO
CREATE DATABASE [Test]
GO
USE [Test]
GO
CREATE TABLE [Test] (
ID INT
, Sub_Links TINYINT
, Link VARCHAR(100)
);
INSERT INTO [Test]
VALUES (1, 5, 'link1.com')
, (2, 2, 'link2.com')
, (3, 4, 'link3.com')
, (4, 1, 'link4.com')
, (4, 1, 'link4.com')
, (5, 2, 'link5.com')
, (6, 4, 'link6.com')
, (7, 3, 'link7.com')
, (7, 3, 'link7.com');
SET NOCOUNT ON
GO
CREATE TABLE #Staging
(
ID INT
, Link VARCHAR(100)
, Sub_Links INT
, GroupNum INT
, SublinkRollingSum TINYINT
)
GO
CREATE CLUSTERED INDEX [StagingOrder] ON #Staging(ID, Link) --Since need to guarantee order, doing this upfront should be more efficient
GO
INSERT INTO #Staging(ID, Link, Sub_Links)
SELECT DISTINCT --Don't include duplicate records
ID
, Link
, Sub_Links
FROM Test
ORDER BY ID, Link
GO
--CREATE INDEX [GroupIndex] ON #Staging(GroupNum, SublinkRollingSum)--Intended to improve performance of below while loop
--GO
WITH FirstRecord AS
(
SELECT TOP(1) *
FROM #Staging
ORDER BY ID, Link
)
UPDATE FirstRecord
SET GroupNum = 1, SublinkRollingSum = Sub_Links --This is the starting point
DECLARE
#CurrentID INT
, #CurrentLink VARCHAR(100)
, #CurrentGroup INT
, #SublinkRollingSum TINYINT
SELECT TOP(1)
#CurrentID = ID
, #CurrentLink = Link
, #CurrentGroup = GroupNum
, #SublinkRollingSum = SublinkRollingSum
FROM #Staging
ORDER BY ID, Link
WHILE (##ROWCOUNT > 0)
BEGIN
UPDATE #Staging
SET SublinkRollingSum = #SublinkRollingSum
, GroupNum = #CurrentGroup
WHERE ID = #CurrentID
AND Link = #CurrentLink
SELECT TOP(1)
#CurrentID = ID
, #CurrentLink = Link
, #CurrentGroup =
CASE
WHEN (#SublinkRollingSum + Sub_Links <= 5)
THEN #CurrentGroup
ELSE #CurrentGroup + 1
END
, #SublinkRollingSum =
CASE
WHEN (#SublinkRollingSum + Sub_Links <= 5)
THEN #SublinkRollingSum + Sub_Links
ELSE Sub_Links
END
FROM #Staging
WHERE ID > #CurrentID
OR (ID = #CurrentID AND Link <> #CurrentLink)
ORDER BY ID, Link
END
SELECT
t.ID
, t.Sub_Links
, t.Link
, s.GroupNum
FROM #Staging S
JOIN Test t ON s.ID = t.ID
AND s.Link = t.Link
ORDER BY t.ID, t.Link
DROP TABLE #Staging
--DROP DATABASE [Test]

SQL: Pinned rows and row number calculation

We have a requirement to assign row number to all rows using following rule
Row if pinned should have same row number
Otherwise sort it by GMD
Example:
ID GMD IsPinned
1 2.5 0
2 0 1
3 2 0
4 4 1
5 3 0
Should Output
ID GMD IsPinned RowNo
5 3 0 1
2 0 1 2
1 2.5 0 3
4 4 1 4
3 2 0 5
Please Note row number for Id's 2 and 4 stayed intact as they are pinned with values of 2 and 4 respectively even though the GMD are not in any order
Rest of rows Id's 1, 3 and 5 row numbers are sorted using GMD desc
I tried using RowNumber SQL 2012 however, it is pushing pinned items from their position
Here's a set-based approach to solving this. Note that the first CTE is unnecessary if you already have a Numbers table in your database:
declare #t table (ID int,GMD decimal(5,2),IsPinned bit)
insert into #t (ID,GMD,IsPinned) values
(1,2.5,0), (2, 0 ,1), (3, 2 ,0), (4, 4 ,1), (5, 3 ,0)
;With Numbers as (
select ROW_NUMBER() OVER (ORDER BY ID) n from #t
), NumbersWithout as (
select
n,
ROW_NUMBER() OVER (ORDER BY n) as rn
from
Numbers
where n not in (select ID from #t where IsPinned=1)
), DataWithout as (
select
*,
ROW_NUMBER() OVER (ORDER BY GMD desc) as rn
from
#t
where
IsPinned = 0
)
select
t.*,
COALESCE(nw.n,t.ID) as RowNo
from
#t t
left join
DataWithout dw
inner join
NumbersWithout nw
on
dw.rn = nw.rn
on
dw.ID = t.ID
order by COALESCE(nw.n,t.ID)
Hopefully my naming makes it clear what we're doing. I'm a bit cheeky in the final SELECT by using a COALESCE to get the final RowNo when you might have expected a CASE expression. But it works because the contents of the DataWithout CTE is defined to only exist for unpinned items which makes the final LEFT JOIN fail.
Results:
ID GMD IsPinned RowNo
----------- --------------------------------------- -------- --------------------
5 3.00 0 1
2 0.00 1 2
1 2.50 0 3
4 4.00 1 4
3 2.00 0 5
Second variant that may perform better (but never assume, always test):
declare #t table (ID int,GMD decimal(5,2),IsPinned bit)
insert into #t (ID,GMD,IsPinned) values
(1,2.5,0), (2, 0 ,1), (3, 2 ,0), (4, 4 ,1), (5, 3 ,0)
;With Numbers as (
select ROW_NUMBER() OVER (ORDER BY ID) n from #t
), NumbersWithout as (
select
n,
ROW_NUMBER() OVER (ORDER BY n) as rn
from
Numbers
where n not in (select ID from #t where IsPinned=1)
), DataPartitioned as (
select
*,
ROW_NUMBER() OVER (PARTITION BY IsPinned ORDER BY GMD desc) as rn
from
#t
)
select
dp.ID,dp.GMD,dp.IsPinned,
CASE WHEN IsPinned = 1 THEN ID ELSE nw.n END as RowNo
from
DataPartitioned dp
left join
NumbersWithout nw
on
dp.rn = nw.rn
order by RowNo
In the third CTE, by introducing the PARTITION BY and removing the WHERE clause we ensure we have all rows of data so we don't need to re-join to the original table in the final result in this variant.
this will work:
CREATE TABLE Table1
("ID" int, "GMD" number, "IsPinned" int)
;
INSERT ALL
INTO Table1 ("ID", "GMD", "IsPinned")
VALUES (1, 2.5, 0)
INTO Table1 ("ID", "GMD", "IsPinned")
VALUES (2, 0, 1)
INTO Table1 ("ID", "GMD", "IsPinned")
VALUES (3, 2, 0)
INTO Table1 ("ID", "GMD", "IsPinned")
VALUES (4, 4, 1)
INTO Table1 ("ID", "GMD", "IsPinned")
VALUES (5, 3, 0)
SELECT * FROM dual
;
select * from (select "ID","GMD","IsPinned",rank from(select m.*,rank()over(order by
"ID" asc) rank from Table1 m where "IsPinned"=1)
union
(select "ID","GMD","IsPinned",rank from (select t.*,rank() over(order by "GMD"
desc)-1 rank from (SELECT * FROM Table1)t)
where "IsPinned"=0) order by "GMD" desc) order by rank ,GMD;
output:
2 0 1 1
5 3 0 1
1 2.5 0 2
4 4 1 2
3 2 0 3
Can you try this query
CREATE TABLE Table1
(ID int, GMD numeric (18,2), IsPinned int);
INSERT INTO Table1 (ID,GMD, IsPinned)
VALUES (1, 2.5, 0),
(2, 0, 1),
(3, 2, 0),
(4, 4, 1),
(5, 3, 0)
select *, row_number () over(partition by IsPinned order by (case when IsPinned =0 then GMD else id end) ) [CustOrder] from Table1
This took longer then I thought, the thing is row_number would take a part to resolve the query. We need to differentiate the row_numbers by id first and then we can apply the while loop or cursor or any iteration, in our case we will just use the while loop.
dbo.test (you can replace test with your table name)
1 2.5 False
2 0 True
3 3 False
4 4 True
6 2 False
Here is the query I wrote to achieve your result, I have added comment under each operation you should get it, if you have any difficultly let me know.
Query:
--user data table
DECLARE #userData TABLE
(
id INT NOT NULL,
gmd FLOAT NOT NULL,
ispinned BIT NOT NULL,
rownumber INT NOT NULL
);
--final result table
DECLARE #finalResult TABLE
(
id INT NOT NULL,
gmd FLOAT NOT NULL,
ispinned BIT NOT NULL,
newrownumber INT NOT NULL
);
--inserting to uer data table from the table test
INSERT INTO #userData
SELECT t.*,
Row_number()
OVER (
ORDER BY t.id ASC) AS RowNumber
FROM test t
--creating new table for ids of not pinned
CREATE TABLE #ids
(
rn INT,
id INT,
gmd FLOAT
)
-- inserting into temp table named and adding gmd by desc
INSERT INTO #ids
(rn,
id,
gmd)
SELECT DISTINCT Row_number()
OVER(
ORDER BY gmd DESC) AS rn,
id,
gmd
FROM #userData
WHERE ispinned = 0
--declaring the variable to loop through all the no pinned items
DECLARE #id INT
DECLARE #totalrows INT = (SELECT Count(*)
FROM #ids)
DECLARE #currentrow INT = 1
DECLARE #assigningNumber INT = 1
--inerting pinned items first
INSERT INTO #finalResult
SELECT ud.id,
ud.gmd,
ud.ispinned,
ud.rownumber
FROM #userData ud
WHERE ispinned = 1
--looping through all the rows till all non-pinned items finished
WHILE #currentrow <= #totalrows
BEGIN
--skipping pinned numers for the rows
WHILE EXISTS(SELECT 1
FROM #finalResult
WHERE newrownumber = #assigningNumber
AND ispinned = 1)
BEGIN
SET #assigningNumber = #assigningNumber + 1
END
--getting row by the number
SET #id = (SELECT id
FROM #ids
WHERE rn = #currentrow)
--inserting the non-pinned item with new row number into the final result
INSERT INTO #finalResult
SELECT ud.id,
ud.gmd,
ud.ispinned,
#assigningNumber
FROM #userData ud
WHERE id = #id
--going to next row
SET #currentrow = #currentrow + 1
SET #assigningNumber = #assigningNumber + 1
END
--getting final result
SELECT *
FROM #finalResult
ORDER BY newrownumber ASC
--dropping table
DROP TABLE #ids
Output:

Get the id of the last record in the data SQL Server

I am trying to get the last ID from at least 4 child-parent relationships between ID's and sum all related ID's quantity. I have tried below -
declare #test table (ID int not null, P_ID int null, Qty int not null)
insert into #test(ID, P_ID, Qty) values
(1 , 11 , 1),
(2 , null, 3),
(11, 21 , 2),
(21, 31 , 1),
(31, null, 3),
(12, null, 4)
select
COALESCE(T2.ID,T1.ID) as ID,
MAX(CASE WHEN T1.P_ID is not null then T1.ID END) as OldID,
SUM(Qty) as Qty
from
#test T1
left join
(select ID from #test
GROUP By ID) T2
on T2.ID = T1.P_ID
group by
COALESCE(T2.ID, T1.ID)
I am getting output -
ID OldID Qty
2 NULL 3
11 1 1
12 NULL 4
21 11 1
31 21 2
But I want my output will be like this where all ID's with no Parent ID in the first row then all previous ID's will show and SUM all relevant ID's quantity -
ID OldID3 OldID2 OldID1 Qty
2 3
12 4
31 21 11 1 7
Could someone please help me to achieve this.
Thanks in advance
Hopefully, this helps you. I have not tested it thoroughly, so apologies for any bugs.
I'm using a Common Table Expression to get the hierarchy information, then using a dynamic SQL I extract the desired number of previous IDs.
DECLARE #test TABLE (ID INT NOT NULL, P_ID INT NULL, Qty INT NOT NULL);
INSERT INTO #test(ID, P_ID, Qty) VALUES
(1 , 11 , 1),
(2 , null, 3),
(11, 21 , 2),
(21, 31 , 1),
(31, null, 3),
(12, null, 4);
IF (OBJECT_ID('tempdb..#hierarchy') IS NOT NULL)
DROP TABLE #hierarchy;
CREATE TABLE #hierarchy (
RootID INT NOT NULL, ID INT NOT NULL, [Qty] INT NOT NULL, SeqIndex INT NOT NULL
);
;WITH hierarchy AS (
SELECT ID, P_ID, Qty, ID [RootID], 0 [SeqIndex]
FROM #test
WHERE P_ID IS NULL
UNION ALL
SELECT child.ID, child.P_ID, child.Qty, parent.RootID, parent.SeqIndex + 1 [SeqIndex]
FROM #test child
JOIN hierarchy parent ON parent.ID=child.P_ID
)
INSERT #hierarchy
SELECT RootID, ID, Qty, SeqIndex
FROM hierarchy;
DECLARE
#DEPTH INT = 3,
#maxSeqIndex INT = (SELECT MAX(SeqIndex) FROM #hierarchy);
IF (#DEPTH = 0)
SELECT RootID, SUM(Qty) [Qty]
FROM #hierarchy
GROUP BY RootID;
ELSE IF (#DEPTH > #maxSeqIndex)
SELECT NULL
ELSE BEGIN
DECLARE #SQL NVARCHAR(MAX) = N'
SELECT
RootID,
';
DECLARE #idx INT = 1;
WHILE #idx <= #DEPTH BEGIN
SET #SQL += N'
(SELECT ID FROM #hierarchy i WHERE i.RootID=o.RootID AND SeqIndex='+CAST(#idx as nvarchar(10))+N') [OldID'+CAST(#maxSeqIndex-#idx+1 as nvarchar(10))+N'],';
SET #idx += 1;
END
SET #SQL += N'
SUM(Qty) [Qty]
FROM #hierarchy o
GROUP BY RootID;';
EXEC sp_executesql #SQL
END
Of course, the dynamic script could be replaced with a hard-coded SQL if that is OK for you.
Note: performance has not been considered

Wrong calculation in Sum()

hi i have 2 table and i want plus it.
Table 1 --> StudentId = 1 ,Score = 10 , 20 ,30 , StudentId = 2 ,Score = 5, 5
Table 2 --> StudentId = 1 ,Score = 5, 10 ,15 , StudentId = 2 ,Score = 15, 25
Total = StudentId = 1 ---> 90 , StudentId = 2 ---> 45
i use this query:
Select Sum(tbl_EvaPoint.Score + tbl_ActPoint.Score ),
tbl_ActPoint.StudentId
From tbl_EvaPoint
JOIN tbl_ActPoint
ON tbl_EvaPoint.StudentId = tbl_ActPoint.StudentId
GROUP BY tbl_ActPoint.StudentId`
everythings is ok but i get wrong sum instead of 90 and 45 i get 180 and 90 or somthings else.
Use UNION instead of JOIN
SELECT student_id, SUM(score)
FROM (SELECT student_id, score FROM Table1
UNION ALL
SELECT student_id, score FROM Table2
) as T
GROUP BY student_id
I think a CTE is more readable, but that is personal preference.
CREATE TABLE #S1 (
StudentID smallint
,Score smallint )
INSERT INTO #S1
SELECT 1, 10;
INSERT INTO #S1
SELECT 1, 20;
INSERT INTO #S1
SELECT 1, 30;
INSERT INTO #S1
SELECT 2, 5
INSERT INTO #S1
SELECT 2, 5;
CREATE TABLE #S2 (
StudentID smallint
,Score smallint )
INSERT INTO #S2
SELECT 1, 5;
INSERT INTO #S2
SELECT 1, 10;
INSERT INTO #S2
SELECT 1, 15;
INSERT INTO #S2
SELECT 2, 15;
INSERT INTO #S2
SELECT 2, 25;
WITH CTE AS (
SELECT
StudentID, Score
FROM #S1
UNION ALL
SELECT
StudentID, Score
FROM #S2 )
SELECT
StudentID
,SUM(Score) AS TotalScore
FROM CTE
GROUP BY StudentID

Increase the performance of an inventory (FIFO) query

My goal is to get the price from item which goes into stock and put the price into out item by (FIFO order by TranDate), then calculate the total price of any line of production (" lineid ").
This is what I have done
-- temp table for result
declare #Test table ( stockID int , OriQty decimal(16,2) ,inuse decimal(16,2) , price decimal(16,2) , lineid int , Inid int )
declare #StockIn table (ID int , StockID int ,qty decimal(16,2),Price decimal(16,2), tranDate Date , running int)
insert into #StockIn(ID , StockID , qty , Price , tranDate , running) values
(1,1 , 15 , 430 , '2014-10-09' , 1),
(2,1 , 10 , 431, '2014-12-09' , 2),
(3,1 , 15 , 432, '2015-02-02' , 3),
(4,2 , 15 , 450, '2014-08-05' , 1),
(5,2 , 6 , 450, '2014-10-09' , 2),
(6,2 , 15 , 452, '2015-02-02' , 3)
-- lineid = line production
declare #StockOut table (ID int , StockID int ,qty decimal(16,2), lineid int, tranDate Date)
insert into #StockOut(ID , StockID ,qty , lineid, tranDate )
values
(1,1 , 20 , 2, '2014-10-10'),
(2,1 , 10 , 4, '2014-12-20'),
(3,2 , 12 , 8, '2014-10-01'),
(4,2 , 3 , 8, '2014-10-01') ;
DECLARE #intFlag INT
SET #intFlag = 1 -- initial of loop
WHILE (#intFlag <= (Select Max(ID) from #StockOut) )
BEGIN
declare #stockID int
declare #ids table (ID int , Inuse decimal(16,2))
declare #lineid int
declare #qtyToRemove decimal(16,2) -- get qty from #StockOut
--get data from #StockOut row by row
select #stockID = StockID , #qtyToRemove = qty , #lineid = lineid from #StockOut where ID = #intFlag;
with cte as (
select *, sum(qty) over (order by tranDate ASC , qty DESC , tranDate ASC Rows UNBOUNDED PRECEDING) - #qtyToRemove
as Total FROM #StockIn Where stockID = #stockID )
-- running FIFO from #StockIn and update QTy when stock is running out
, RunningFIFO as (
select cte.StockID , cte.qty AS OriginalQty , Case when
case when 0 > total then cte.qty else cte.qty-total End > 0 then case when 0 > total then cte.qty else cte.qty-total End else 0 End As Inuse
, cte.Price , #lineid AS lineid , id
from cte
)
-- insert result into result table
insert into #test (stockID , OriQty ,inuse , cte.Price , lineid ,Inid ) OUTPUT inserted.Inid , inserted.inuse into #ids select * from RunningFIFO Where Inuse > 0
UPDATE #StockIn set qty = qty - inuse from #ids A inner join #StockIn B on A.ID = b.ID
SET #intFlag = #intFlag + 1
END
Select sum(inuse * price) AS total , lineid from #Test group by lineid
But when data are more than a thousand, this query runs super slow.
How could I increase the performance of this query?