SQL Server 2008 - Not Always Getting Max - sql-server

I have a query that should return the MAX CloseDate from a table that has many close dates, grouped by the ShipmentNumber column.
I seem to be getting more than one ShipmentNumber in the results when I include the Notes column.
table WorkOrders
WorkOrderID, ProjectNumber, ShipmentNumber, CloseDate, WorkOrderNotes
1, 884, 123-01, 2016-04-01, Note A
2, 884, 123-01, 2016-04-02, Note B
3, 884, 123-02, 2016-04-01, Note A
table Projects
ProjectNumber, Name
884, Project A
Query:
SELECT p.id, p.name, WO.ShipmentNumber,MAX(WO.CloseDate) AS CloseDate,
CAST(WO.WorkOrderNotes AS NVARCHAR(100)) AS WorkOrderNotes
FROM DA.dbo.WorkOrders AS WO
LEFT JOIN Projects.dbo.project_primary AS p ON p.id = WO.ProjectNumber
WHERE WO.CloseDate >= '2016-03-01'
AND WO.CloseDate IS NOT NULL
GROUP BY WO.ShipmentNumber, p.name, p.id, CAST(WO.WorkOrderNotes AS NVARCHAR(100)) ;
Results:
884, Project A, 123-01, 2016-04-01, Note A <-- Should not be here
884, Project A, 123-01, 2016-04-02, Note B
884, Project A, 123-02, 2016-04-01, Note A

#Irb got this in the comments; you're grouping by WO.ShipmentNumber and have different values for this for the first and third line; thus getting both.
If you want only the WO record with the max close date, try this:
SELECT p.id
, p.name
, WO.ShipmentNumber
, WO.CloseDate
FROM (
select ProjectNumber
, ShipmentNumber
, CloseDate
, CAST(WorkOrderNotes AS NVARCHAR(100)) AS WorkOrderNotes
, row_number() over (partition by ProjectNumber order by CloseDate desc) r
from DA.dbo.WorkOrders
WHERE WO.CloseDate >= '2016-03-01'
AND WO.CloseDate IS NOT NULL
) AS WO
LEFT JOIN Projects.dbo.project_primary AS p
ON p.id = WO.ProjectNumber
WHERE WO.r = 1 --only return the record with the most max CloseDate
GROUP BY p.id
, p.name
, WO.ShipmentNumber
, WO.WorkOrderNotes

Related

When joining tables adapt the "on" statement depending on the query results

I have 2 tables:
Table_1 with columns col_A, col_B , col_C , col_D , col_E
Table_2 with columns col_A, col_B , col_C , col_D , col_F
I would like to join them on columns col_A, col_B , col_C , col_D.
For the rows in Table_1 that do not get joined this way (as they don't have a match in Table_2), I would like to join them only on columns col_A, col_B , col_C.
If there are still rows in Table_1 that did not get joined, i would like to join them only on columns col_A, col_B.
And once that is done and there are still rows in Table_1 that did not get joined, i would like to join them only on column col_A.
I wrote the following script where i use a new table to get this result.
Is there is a more efficient way to do this? Preferably by creating a view, not a table?
create table new_table (col_A nvarchar(50) , col_B nvarchar(50) , col_C nvarchar(50)
, col_D nvarchar(50) , col_E nvarchar(50) , col_F nvarchar(50) )
go
insert into new_table
select Table_1.* , Table_2.col_F
from Table_1
inner join Table_2
on Table_1.col_A=Table_2.col_A
and Table_1.col_B=Table_2.col_B
and Table_1.col_C=Table_2.col_C
and Table_1.col_D=Table_2.col_D
go
insert into new_table
select Table_1.* , Table_2.col_F
from Table_1
inner join Table_2
on Table_1.col_A=Table_2.col_A
and Table_1.col_B=Table_2.col_B
and Table_1.col_C=Table_2.col_C
where concat (Table_1.col_A, Table_1.col_B , Table_1.col_C , Table_1.col_D , Table_1.col_E
not in (select concat (col_A, col_B , col_C , col_D , col_E) from new_table)
go
insert into new_table
select Table_1.* , Table_2.col_F
from Table_1
inner join Table_2
on Table_1.col_A=Table_2.col_A
and Table_1.col_B=Table_2.col_B
where concat (Table_1.col_A, Table_1.col_B , Table_1.col_C , Table_1.col_D , Table_1.col_E
not in (select concat (col_A, col_B , col_C , col_D , col_E) from new_table)
go
insert into new_table
select Table_1.* , Table_2.col_F
from Table_1
inner join Table_2
on Table_1.col_A=Table_2.col_A
where concat (Table_1.col_A, Table_1.col_B , Table_1.col_C , Table_1.col_D , Table_1.col_E
not in (select concat (col_A, col_B , col_C , col_D , col_E) from new_table)
go
You could join them on just colA and then assign some different numbers:
WITH cte AS(
SELECT
CASE WHEN t1.D = t2.D THEN 100 ELSE 0 END +
CASE WHEN t1.C = t2.C THEN 10 ELSE 0 END +
CASE WHEN t1.B = t2.B THEN 1 ELSE 0 END as whatMatched,
*
FROM
t1 JOIN t2 on t1.A = t2.A
)
Now if a row got 111 we know that all (ABCD) matched, got 0 then only A matched etc..
So we can ask for only some rows:
SELECT * FROM cte WHERE whatmatched IN (111,11,1,0)
And lastly if there were multiples (matching on just A might mean there are duplicates), we can assign a row number to them in descending order and only take the first row:
SELECT x.* FROM
(SELECT *, ROW_NUMBER() OVER(ORDER BY whatmatched DESC) rown FROM cte WHERE whatmatched IN (111,11,1,0)) x
WHERE x.rown = 1
If it suits you better to use letters
we can assess the matches, choose only A, AB, ABC, or ABCD, then pick the most specific one by looking at the LENgth of the match string:
WITH cte AS(
SELECT
'A' +
CASE WHEN t1.B = t2.B THEN 'B' ELSE '' END +
CASE WHEN t1.C = t2.C THEN 'C' ELSE '' END +
CASE WHEN t1.D = t2.D THEN 'D' ELSE '' END as whatMatched,
*
FROM
t1 JOIN t2 on t1.A = t2.A
)
SELECT x.* FROM
(SELECT *, ROW_NUMBER() OVER(ORDER BY LEN(whatmatched) DESC) rown FROM cte WHERE whatmatched IN ('A','AB','ABC','ABCD')) x
WHERE x.rown = 1
If you want ties (i.e. a row from t1 that matches two rows from t2 because their A/B/C is the same and D differs, use DENSE_RANK instead of ROW_NUMBER so they end up tied for first place

Using ROW_NUMBER() to remove duplicates in SQL server

My current query returns too many lines per Subject_ID, so I want to use ROW_NUMBER() to limit the resulting set to 1 line per Subject_ID. I've added this line to my SELECT statement:
, ROW_NUMBER() over(partition by CS.Subject_ID order by CS.Subject_ID) rn
But when I try to put WHERE rn = 1 anywhere in the FROM statement, I get the error:
Incorrect syntax near the keyword 'WHERE'
And when I try to change it to AND rn = 1 (and add it on to another AND/OR line) I get the error:
Invalid column name 'rn'
So my first question is: When I add a field to my SELECT statement using that ROW_NUMBER() line, what table does this column belong to? Do I need to append it to something like Table.rn? My second question is where should I put this rn = 1 line and how should I write it in?
Full query:
SELECT
Groups.Group_Name
, CT.Created
, CT.Subject_Id
INTO #temp
FROM SubjectZ_Task CT
INNER JOIN
SubjectZ_Task_Users On CT.SubjectZ_Task_Id = SubjectZ_Task_Users.SubjectZ_Task_Id
INNER JOIN
Groups ON Groups.Group_ID = SubjectZ_Task_Users.Group_Reference
WHERE Group_Name LIKE 'Team 1'
AND CT.Created >= '1/1/2019' AND CT.Created < DATEADD(Day,1,'12/31/2019')
GROUP BY Groups.group_name, CT.Created, CT.Subject_ID
SELECT
CT.Group_Name
, CT.Created
, CS.Topic_Start_Date
, CS.Subject_ID
, P.FirstName
, P.LastName
, CS.Subject_Match_ID
, SubjectX.Firstname AS SubjectX_firstname
, CS.SubjectY
, AEC.AEC AS Max_AEC
, SubjectX.Email_id As SubjectX_Email
, Phone.Phone
, ROW_NUMBER() over(partition by CS.Subject_ID order by CS.Subject_ID) rn
FROM #temp CT
LEFT JOIN QE_Topic_Summary CS ON CS.Subject_ID = CT.Subject_Id
AND (Topic_Status LIKE 'In Progress'
OR Topic_Status LIKE 'Pending')
AND CS.Topic_Start_Date >= DATEADD(Day,-60,CT.Created) AND CS.Topic_Start_Date <= DATEADD(Day,60,CT.Created)
INNER JOIN Subjects P ON P.Subject_ID = CS.Subject_ID
LEFT JOIN Subjects SubjectX ON SubjectX.Subject_ID = CS.SubjectX_ID
LEFT JOIN QE_TB_MAX_AEC AEC ON AEC.Subject_ID = CS.Subject_ID
INNER JOIN Subject_Identifiers PI ON PI.Subject_ID = P.Subject_ID
LEFT JOIN Subject_Identifiers PIP ON PIP.Subject_ID = SubjectX.Subject_ID
LEFT JOIN Subject_Phone Phone On Phone.Subject_ID = P.Subject_ID WHERE Phone.Voice = 1
drop table #temp
I don't see a reference to rn in your WHERE clause, but my guess is that you need to wrap it in another query like so:
SELECT *
FROM(
SELECT
CT.Group_Name
, CT.Created
, CS.Topic_Start_Date
, CS.Subject_ID
, P.FirstName
, P.LastName
, CS.Subject_Match_ID
, SubjectX.Firstname AS SubjectX_firstname
, CS.SubjectY
, AEC.AEC AS Max_AEC
, SubjectX.Email_id As SubjectX_Email
, Phone.Phone
, ROW_NUMBER() over(partition by CS.Subject_ID order by CS.Subject_ID) rn
FROM #temp CT
LEFT JOIN QE_Topic_Summary CS ON CS.Subject_ID = CT.Subject_Id
AND (Topic_Status LIKE 'In Progress'
OR Topic_Status LIKE 'Pending')
AND CS.Topic_Start_Date >= DATEADD(Day,-60,CT.Created) AND CS.Topic_Start_Date <= DATEADD(Day,60,CT.Created)
INNER JOIN Subjects P ON P.Subject_ID = CS.Subject_ID
LEFT JOIN Subjects SubjectX ON SubjectX.Subject_ID = CS.SubjectX_ID
LEFT JOIN QE_TB_MAX_AEC AEC ON AEC.Subject_ID = CS.Subject_ID
INNER JOIN Subject_Identifiers PI ON PI.Subject_ID = P.Subject_ID
LEFT JOIN Subject_Identifiers PIP ON PIP.Subject_ID = SubjectX.Subject_ID
LEFT JOIN Subject_Phone Phone On Phone.Subject_ID = P.Subject_ID
WHERE Phone.Voice = 1
)t
WHERE t.rn = 1

How to write this SQL Server query: Add values in unique rows?

I have a query like below. The relation between table are:
Each truck may have multiple drivers. Table List connects the each row in table Truck with rows in table Driver. Now I want to get the count of unique Trucks under certain condition, and the total size of the unique Trucks under that condition.
Here is what I have:
SELECT t.Year AS [Year]
, t.Month AS [Month]
, t.Day AS [Day]
-- Count will not count NULL
, COUNT( DISTINCT (CASE WHEN (t.Sent = 1 AND r.Internal=1) THEN L.TruckId
ELSE NULL
END) ) AS [Count]
, SUM(CASE WHEN (t.Sent = 1 AND r.Internal = 1) THEN t.Size
END) AS [Size]
FROM Truck t
INNER JOIN List L ON t.Id = L.TruckId
INNER JOIN Driver r ON L.DriverId = r.Id
GROUP BY t.Year, t.Month, t.Day
the COUNT is correct, but the SUM is not.
My question is how to get this SUM? And I do not want to write 2 queries and join them.
Thanks
You can try query like below:
; with cte as (
SELECT
DISTINCT
t.Year AS [Year]
, t.Month AS [Month]
, t.Day AS [Day]
, L.TruckId,
, t.Size
FROM Truck t
INNER JOIN List L ON t.Id = L.TruckId
INNER JOIN Driver r ON L.DriverId = r.Id
WHERE t.Sent = 1 AND r.Internal=1
)
select
Year
, Month
, Day
, count(TruckId) AS [Count]
, sum(Size) AS [Size]
from cte
group by Year, Month, Day

SQL Server: How to show list of manager name separated by comma

i have to show employee name and his manager name hierarchy separated by comma.
if ram is top manager and ram is sam manager and sam is rahim manager then i would like to have output like
Desired output
EMP Name Manager's Name
--------- ---------------
Rahim Sam,Ram
Sam Ram
Ram No manager
i got script which show the employee and his manager name. here is script
;WITH EmployeeCTE AS
(
Select ID,Name,MgrID, 0 as level FROM #Employee
WHERE ID=3
UNION ALL
Select r.ID,r.Name,r.MgrID, level+1 as level
FROM #Employee r
JOIN EmployeeCTE p on r.ID = p.MgrID
)
Select e1.Name
,ISNULL(e2.Name,'Top BOSS') as [Manager Name]
,row_number() over (order by e1.level desc) as [Level]
from EmployeeCTE e1
left join EmployeeCTE e2 on e1.MgrID=e2.ID
Output
Name Manager Name Level
Simon Top BOSS 1
Katie Simon 2
John Katie 3
i also know how to show comma separated list. here is one sample script.
SELECT
PNAME,
STUFF
(
(
SELECT ',' + Mname
FROM Myproducts M
WHERE M.PNAME = P.PNAME
ORDER BY Mname
FOR XML PATH('')
), 1, 1, ''
) AS Models
FROM
Myproducts p
GROUP BY PNAME
now some tell me how could i merge two script to get the desired output. thanks
CREATE TABLE #EMP (
EmpID INT
, ManagerID INT
, Name NVARCHAR(50) NULL
);
INSERT INTO #EMP (EmpID, ManagerID, Name)
VALUES
( 1, NULL, 'John')
, (2, 1, 'Katie')
, (3, 2, 'Simon');
SELECT *
FROM
#EMP;
WITH a AS (
SELECT
EmpID
, Name
, ManagerID
, CONVERT(NVARCHAR(MAX),'') AS ManagerChain
FROM
#Emp
WHERE
ManagerID IS NULL
UNION ALL
SELECT
e.EmpID
, e.Name
, e.ManagerID
, CASE
WHEN a.ManagerChain ='' THEN a.Name
ELSE CONCAT(a.Name, CONCAT(',',a.ManagerChain))
END
FROM
#Emp e
JOIN a ON e.ManagerID = a.EmpID
)
SELECT
a.Name
, IIF(a.ManagerChain='','No Manager',a.ManagerChain) AS ManagerChain
FROM
a;
DROP TABLE #EMP;
Assuming a table structure of
DECLARE #Employee TABLE(
ID INT,
Name VARCHAR(10),
MgrID INT)
INSERT INTO #Employee
VALUES (1,'Ram',NULL),
(2,'Sam',1),
(3,'Rahim',2);
You can use
WITH EmployeeCTE
AS (SELECT ID,
Name,
MgrID,
0 AS level,
CAST('No manager' AS VARCHAR(8000)) AS [Managers Name]
FROM #Employee
WHERE MgrID IS NULL
UNION ALL
SELECT r.ID,
r.Name,
r.MgrID,
level + 1 AS level,
CAST(P.Name + CASE
WHEN level > 0
THEN ',' + [Managers Name]
ELSE ''
END AS VARCHAR(8000))
FROM #Employee r
JOIN EmployeeCTE p
ON r.MgrID = p.ID)
SELECT *
FROM EmployeeCTE

query is not returning distinct record

Hi can you please take a look why my query is not returning distinct record. i want result with following condition OE1='SCHEDCHNG', need only recent records per orderid or ordernum means only one record per ordernum or orderid and also dropdate is null. My query is as below
select DISTINCT TOP 100 OE.ORDERID,OE.ID,OE.ORDERNUM,OE.OE4 from OrderExports OE
inner join (
select ORDERNUM, max(OE4) as MaxDate
from OrderExports
group by ORDERNUM
) tm
on OE.ORDERNUM = tm.ORDERNUM and OE.OE4 = tm.MaxDate
inner join orde_ O on OE.ORDERID = O.ORDERID
WHERE OE1='SCHEDCHNG' AND O.DROPDATE is null
Pretty sparse on details here but I think you are wanting something along these lines.
with SortedResults as
(
select OE.ORDERID
, OE.ID
, OE.ORDERNUM
, OE.OE4
, ROW_NUMBER() over(partition by OE.ORDERID, OE.ORDERNUM order by OE.OE4 desc) as RowNum
from OrderExports OE
inner join
(
select ORDERNUM
, max(OE4) as MaxDate
from OrderExports
group by ORDERNUM
) tm on OE.ORDERNUM = tm.ORDERNUM and OE.OE4 = tm.MaxDate
inner join orde_ O on OE.ORDERID = O.ORDERID
WHERE OE1='SCHEDCHNG'
AND O.DROPDATE is null
)
select ORDERID
, ID
, ORDERNUM
, OE4
from SortedResults
where RowNum = 1
You can try using max and group by as below :
SELECT a.ID, max(a.ORDERID) as OrderID, max(a.ORDERNUM) as OrderNum,MAX(OE.OE4) as OE4 FROM
(
--your query
) a
group by a.ID

Resources