SQL CASE mixes up my grouping - sql-server

The problem situates itself at the 4th line of the SELECT statement: CASE WHEN ct.TransactionReason=622 THEN ABS(ct.netquantity) ELSE c.RealNetWeight END AS NetWeight
When I add this line to the statement, my grouping will change. Instead of returning one line it now gives me back the amount of lines of different c.realnetweight.
Problem is that I only want to return one line. Sort of like a coalesce that when there is a ct.transactionreason = 622, it should give me ABS(ct.netquantity), otherwise the c.realnetweight. Code can be found beneath, suggestions would be very helpful. Thanks.
SELECT CASE WHEN P.Wrapped = 1 THEN T.[Level]+1 ELSE T.[Level] END AS [Level]
, #CoilId AS CoilId
, c.SupplierCoilID
, CASE WHEN ct.TransactionReason=622 THEN ABS(ct.netquantity) ELSE c.RealNetWeight END AS NetWeight
, C.RealGrossWeight
, p1.Description
, p1.product
, s.StackID
, s.ProductID
, s.Weight
, P.Product
, P.Description AS 'ProductDescription'
, COUNT(t.BlankId) AS 'NumberOfBlanks'
, c1.Description as 'Status'
, pv.ProductionWeight
, pv.BlankWeight
, t.BlankStatus
FROM #Trace T
INNER JOIN SKUTraceability SKUT ON SKUT.SKUID = T.SKUID
INNER JOIN Stack s ON SKUT.StackID = s.StackID
INNER JOIN Product p ON s.ProductID = p.ProductID
INNER JOIN Coil c ON c.CoilID=#CoilId
INNER JOIN CoilTransaction ct on ct.CoilID=#CoilId
INNER JOIN Product p1 ON c.ProductID=p1.ProductID
INNER JOIN Code c1 ON t.BlankStatus=c1.codenumber AND c1.codetypeid=17
INNER JOIN #ProductVersion pv ON pv.ProductID=p.ProductId AND s.ProductVersion = pv.ProductVersion
WHERE t.BlankId IS NOT NULL
GROUP BY T.[Level]
, c.SupplierCoilID
, CASE WHEN ct.TransactionReason=622 THEN ABS(ct.netquantity) ELSE c.RealNetWeight END
, c.RealGrossWeight
, p1.Description
, p1.product
, s.StackID
, s.ProductID
, s.Weight
, p.Product
, p.Description
, c1.Description
, pv.ProductionWeight
, pv.BlankWeight
, p.Wrapped
, t.BlankStatus

Hard to answer without understanding your table structures however, it appears that CoilTransaction is some sort of transaction table, i.e. a single product can have many transactions.
In your SELECT query, the line causing you issues, is the only line that references your CoilTransaction table therefore I believe, the reason you're returning multiple rows is because you're grouping on a value that is not unique. Also, are transactions individual items because you seem to have a quantity column on the table.
In short, you can't get the grouping you want by including those columns from your transaction table. You would need to elaborate more on what you're trying to accomplish for us to give a more suitable solution. What does that line mean?

For at least one CoilID in table Coil, you will have more than one value in the field netquantity in the table CoilTransaction. This is what is causing the increase in the number of records returned when you include this field in your CASE statement.
I would recommend finding the netquantity value that you want from CoilTransaction in a CTE, and then bringing this in to your CASE statement. For example:
;WITH transaction_summary AS (
SELECT
ct.CoilID,
ct.TransactionReason,
MAX(ct.netquantity) -- choose your aggregate function here
FROM
CoilTransaction ct
GROUP BY
ct.CoilID,
ct.TransactionReason
)
...

Related

Resulting nulls on full join not being replaced

I have a set of select queries using full join (required) and would like to replace the resulting nulls with something else (in the following example, it should be "empty").
For the first column (and all others, honestly) I have tried using isnull(), coallesce(), case when and even try_convert, but the result is always null. I'm ok with null, as in this particular case means that the results from the first query don't exist the second query, which is my goal.
There are following, identical queries, also full join 'd, so a line in the first query may not be in the second query but may be in the third of fourth queries.
Here is the select statement
SELECT *
FROM (SELECT Isnull(1, 'empty') AS SubGroup
, table2.lineintid AS OrderByThis2nd
, table2.HeaderStamp AS HeaderLink
, table2.linestamp AS LineID
, table2.lprocessname AS LineProcName
, table2.lprocessno AS LineProcNumber
, table2.productid AS ProdId
, table2.prodamount AS QTT
, table2.prodval AS UnitPrice
FROM table2 (nolock)
INNER JOIN table1 ON table2.headerstamp = table1.headerstamp
WHERE table1.lprocessname = 'Phase 1')Proc1L
FULL JOIN (SELECT Isnull(2, 'empty') AS SubGroup
, table2.lineintid AS OrderByThis2nd
, table2.linestamp AS LineID
, table2.prevlstamp AS PrecedingLine
, table2.lprocessname AS LineProcName
, table2.lprocessno AS LineProcNumber
, table2.productid AS ProdId
, table2.prodamount AS QTT
, table2.prodval AS UnitPrice
FROM table2 (nolock)
INNER JOIN table1 ON table2.headerstamp = table1.headerstamp
WHERE table1.lprocessname = 'Phase 2'
AND Year(table2.linedate) = '2018')Proc2L ON Proc1L.LineID = Proc2L.PrecedingLine
ORDER BY 1 DESC
, 2
This database is in MS SQL 2014.
Any ideas are appreciated. Thank you very much!
Try using ISNULL function in the outer query. Instead of
select * from
use
Select isnull(col1, 'x'), etc
from

Merge Join Operation in SQL Query costing 60%+ of query

I am trying to optimize a query that looks pretty simple but the merge query operation is taking the lion's share of the query time. I only am receiving about 1600 results a run and it's taking 25 seconds. I am trying to get the cost and time of this down by 50%. I have tried to use the top 2000 trick to narrow down results and I made sure we are scanning all indexes. I know that seeks would be better but the scans are under 1% of the query.
Here is the plan and SQL.
https://www.brentozar.com/pastetheplan/?id=Ske3IIOQZ
OrderApprovals_View
SQL for the view:
SELECT dbo.SVC_OrderApprovals.ApprovalID ,
dbo.SVC_OrderApprovals.OrderID ,
dbo.SVC_OrderApprovals.CLSItem ,
dbo.SVC_OrderApprovals.CustNum ,
dbo.SVC_OrderApprovals.ReqQuantity ,
dbo.SVC_OrderApprovals.ReqShipDate ,
dbo.SVC_OrderApprovals.UM ,
dbo.SVC_OrderApprovals.CSR ,
dbo.SVC_OrderApprovals.ShipLoc ,
dbo.SVC_OrderApprovals.ApprovalType ,
dbo.SVC_OrderApprovals.ApprovalGroup ,
dbo.SVC_OrderApprovals.CreatedBy ,
dbo.SVC_OrderApprovals.CreateDate ,
dbo.SVC_OrderApprovals.CreatedPC ,
dbo.SVC_OrderApprovals_SC_Notes.SC_Notes ,
dbo.SVC_OrderApprovals_Status.Status ,
CASE WHEN [Status] <> 'NEW' THEN SVC_OrderApprovals_Status.CreatedBy
ELSE NULL
END AS ReviewedBy ,
CASE WHEN [Status] <> 'NEW' THEN SVC_OrderApprovals_Status.CreateDate
ELSE NULL
END AS ReviewDate ,
CASE WHEN [Status] <> 'NEW' THEN SVC_OrderApprovals_Status.CreatedPC
ELSE NULL
END AS ReviewedPC ,
dm_Core.dbo.core_CLSItemData.ItemDescription ,
dm_Core.dbo.core_CustMaster.CustName ,
dbo.SVC_OrderApprovals.SCTeam ,
dbo.SVC_OrderApprovals_Status.CreateDate AS StatusCreateDate ,
dbo.SVC_OrderApprovals_SC_Notes.CreateDate AS SCNoteCreateDate ,
dbo.SVC_OrderApprovals_Approval_Notes.ApprovalNote ,
dbo.SVC_OrderApprovals_Approval_Notes.CreateDate AS ApprovalNoteCreateDate
FROM dbo.SVC_OrderApprovals_Current
INNER JOIN dbo.SVC_OrderApprovals ON dbo.SVC_OrderApprovals_Current.RecordID = dbo.SVC_OrderApprovals.RecordID
LEFT OUTER JOIN dbo.SVC_OrderApprovals_Approval_Notes ON dbo.SVC_OrderApprovals.ApprovalID = dbo.SVC_OrderApprovals_Approval_Notes.ApprovalID
LEFT OUTER JOIN dm_Core.dbo.core_CustMaster ON dbo.SVC_OrderApprovals.CustNum = dm_Core.dbo.core_CustMaster.CustNum
LEFT OUTER JOIN dbo.SVC_OrderApprovals_Status ON dbo.SVC_OrderApprovals.ApprovalID = dbo.SVC_OrderApprovals_Status.ApprovalID
LEFT OUTER JOIN dbo.SVC_OrderApprovals_SC_Notes ON dbo.SVC_OrderApprovals.ApprovalID = dbo.SVC_OrderApprovals_SC_Notes.ApprovalID
LEFT OUTER JOIN dm_Core.dbo.core_CLSItemData ON dbo.SVC_OrderApprovals.CLSItem = dm_Core.dbo.core_CLSItemData.CLSItem;

Select Newest Record

I have two tables (Journal and Incident). Each incident may have more than one journal entry. I want to select the record and the most recent journal data.
The where section at the bottom is what filters the incidents I want to see. Of those, I want the journal values associated with the most recent journal entry.
This is an amalgam of code I've found on here, but when I run it I get a "Query execution failed for dataset 'DataSet1'. Unfortunately, I don't have access to the log files to see if there are clues there.
Any help is appreciated. I think I may have it nested wrong.
SELECT
b.IncidentNumber
,a.Subject
,a.CreatedDateTime
,b.SubCategory
,b.EffectiveDueDate
,b.NextActionDate
,b.ProfileFullName
FROM
(
SELECT
b.IncidentNumber
,a.Subject
,a.CreatedDateTime
,rn = row_number() OVER (PARTITION by b.IncidentNumber ORDER BY
a.CreatedDateTime DESC)
,b.SubCategory
,b.EffectiveDate
,b.NextActionDate
,b.ProfileFullName
FROM
Journal a LEFT JOIN Incident b ON
a.ParentRecordNumber = b.IncidentNumber
WHERE a.Category LIKE '%KANBAN%'
AND (b.Status LIKE' %Waiting%' OR b.status LIKE '%Active%')
AND b.SubCategory <> 'User Termination'
AND b.SubCategory <> 'Res Temp Termination'
AND a.Subject LIKE 'UP |%'
) X
WHERE rn = 1
Few things:
Outer most selected values should be from inline view aliased "X" No a. or b. as those alias only are in scope to the in inner query. (except when using coorlation but that's 1 level only I believe)
You either need to right join instead of left or change the order of the tables. I believe you want all incidents and the MOST recent Journal; not all journals and the related incident if one exists. thus I changed the order.
Lastly when using outer joins, you can only put limits on the all records table of the outer join. Where clause criteria the OUTER joined tables will cause the null records generated by the outer join to be excluded. To resolve this you must move the limiting criteria to the join or use an 'or' statement to check for null (it's cleaner to move it to the join). Think of it is applying the limit before the join occurs so Null records from incident are kept. otherwise the outer join simulates a INNER JOIN by excluding those records not in both tables (or in this case in incident but not in journal)
.
SELECT x.IncidentNumber --alias x not a/b as the from is aliased as 'X'
, x.Subject
, x.CreatedDateTime
, x.SubCategory
, x.EffectiveDueDate
, x.NextActionDate
, x.ProfileFullName
FROM (SELECT b.IncidentNumber
, a.Subject
, a.CreatedDateTime
, rn = row_number() OVER (PARTITION by b.IncidentNumber
ORDER BY a.CreatedDateTime DESC)
, b.SubCategory
, b.EffectiveDate
, b.NextActionDate
, b.ProfileFullName
FROM Incident b --switched the order I think you want all incidents and if a journal exists it's value.
LEFT JOIN Journal a
ON a.ParentRecordNumber = b.IncidentNumber
-- Since A is on the if match found to B, we need to move this to the join or we lose the records created from the outer join.
AND a.Category LIKE '%KANBAN%'
AND a.Subject LIKE 'UP |%'
--moved some where clause criteria to the join Since B is on the "all records side" of the outer join we can leave B in the where clause.
WHERE (b.Status LIKE' %Waiting%' OR b.status LIKE '%Active%')
AND b.SubCategory <> 'User Termination'
AND b.SubCategory <> 'Res Temp Termination') X
WHERE rn = 1
If you are not getting records from here, then I'd start removing some of the limiting criteria to ensure the query is functioning as desired and then add back in limits to see what's causing no records to be found.
I've finally got this report working as expected. It took a few iterations to get the query working, but it's doing what it should, now. Many thanks for your assist. I would have never gotten there without it!
SELECT x.IncidentNumber
, x.Subject
, x.CreatedDateTime
, x.SubCategory
, x.ProfileFullName
, x.PropertyNumber
, x.Status
, x.EffectiveDueDate
FROM (SELECT b.IncidentNumber
, a.Subject
, a.CreatedDateTime
, rn = row_number() OVER (PARTITION by b.IncidentNumber
ORDER BY a.CreatedDateTime DESC)
, b.SubCategory
, b.ProfileFullName
, b.PropertyNumber
, b.Status
, b.EffectiveDueDate
FROM Incident b
RIGHT JOIN Journal a
ON a.ParentRecordNumber = b.IncidentNumber
AND a.Category LIKE '%KANBAN%'
AND a.Subject LIKE 'UP |%'
WHERE (b.Status LIKE' %Waiting%' OR b.status LIKE '%Active%')
) x
WHERE rn = 1

T-SQL: Ugly SQL

EDIT: Just so folks understand, I'm not worried about the formatting, I'm worried about the usage of the GROUP By and the usage of the aggregate fields when it doesn't make a whole lot of sense.
I've been tasked with making some SQL more readable. While I generally know what to do, this particular query escapes me. The gist of the query involves the writer grouping by a whole bunch of fields, and adding those fields to the query results. For fields that he/she doesn't GROUP BY, they use a MIN aggregate function I guess to "make the error go away"
MIN(ISNULL(dbo.V_CONNECT_ContactPartnerDetail_0010.SAPNr, N'')) AS sapkunr,
My difficulty comes from the fact that I can stuff the GROUP BY into a CTE, and then branch out from there, but I've never gotten the row counts to match up between the query I've created and the original one. Any help on making this SQL more readable and making its intent more clear (no functions to make the error go away) would be greatly appreciated.
SELECT dbo.V_CONNECT_ContactPartnerDetail_0010.ID_FI AS firmencode,
dbo.V_CONNECT_ContactPartnerDetail_0010.ID_KP AS partnercode,
dbo.V_CONNECT_ContactPartnerDetail_0010.Nachname,
Min(Isnull(dbo.V_CONNECT_ContactPartnerDetail_0010.Vorname, '')) AS vname,
Min(CASE V_CONNECT_ContactPartnerDetail_0010.Anrede
WHEN 'Frau' THEN 2
ELSE 1
END) AS anrede,
Min(Isnull(dbo.V_CONNECT_ContactPartnerDetail_0010.EMail, N'')) AS mail,
Min(Isnull(dbo.V_CONNECT_ContactPartnerDetail_0010.SAPNr, N'')) AS sapkunr,
Isnull(dbo.V_CONNECT_ContactPartnerDetail_0010.Titel, N'') AS titel
FROM dbo.V_CONNECT_ContactPartnerDetail_0010
INNER JOIN dbo.V_CONNECT_ContactPartnerPivot
ON dbo.V_CONNECT_ContactPartnerDetail_0010.ID_C005 = dbo.V_CONNECT_ContactPartnerPivot.ID_C005
LEFT OUTER JOIN dbo.V_CONNECT_Firmen_PZ_Download
ON dbo.V_CONNECT_ContactPartnerDetail_0010.ID_VF = dbo.V_CONNECT_Firmen_PZ_Download.ID_VF
WHERE ( dbo.V_CONNECT_ContactPartnerDetail_0010.VKO = '0010' )
GROUP BY dbo.V_CONNECT_ContactPartnerDetail_0010.ID_FI,
dbo.V_CONNECT_ContactPartnerDetail_0010.ID_KP,
dbo.V_CONNECT_ContactPartnerDetail_0010.Nachname,
dbo.V_CONNECT_ContactPartnerDetail_0010.Ort,
dbo.V_CONNECT_ContactPartnerPivot.flg_spl,
dbo.V_CONNECT_ContactPartnerPivot.flg_ha,
dbo.V_CONNECT_ContactPartnerPivot.flg_fu,
dbo.V_CONNECT_ContactPartnerPivot.flg_ma,
dbo.V_CONNECT_ContactPartnerPivot.flg_ph,
Isnull(dbo.V_CONNECT_ContactPartnerDetail_0010.Titel, N'')
This is much more "readable" to me
SELECT cpd.ID_FI AS firmencode
, cpd.ID_KP AS partnercode
, cpd.Nachname AS Nachname
, MIN(ISNULL( cpd.Vorname ,'')) AS vname
, MIN(CASE cpd.Anrede WHEN 'Frau' THEN 2 ELSE 1 END) AS anrede
, MIN(ISNULL( cpd.EMail ,N'')) AS mail
, MIN(ISNULL( cpd.SAPNr ,N'')) AS sapkunr
, ISNULL( cpd.Titel ,N'') AS titel
FROM dbo.V_CONNECT_ContactPartnerDetail_0010 cpd
JOIN dbo.V_CONNECT_ContactPartnerPivot cpp
ON cpd.ID_C005 = cpp.ID_C005
LEFT
JOIN dbo.V_CONNECT_Firmen_PZ_Download fpd
ON fpd.ID_VF = cpd.ID_VF
WHERE cpd.VKO = '0010'
GROUP
BY cpd.ID_FI
, cpd.ID_KP
, cpd.Nachname
, cpd.Ort
, cpp.flg_spl
, cpp.flg_ha
, cpp.flg_fu
, cpp.flg_ma
, cpp.flg_ph
, ISNULL(cpd.Titel ,N'')
EDIT
If I was "tasked with making some SQL more readable", I'd start with the changes above.
Beyond that, it's not clear why the GROUP BY clause includes expression that aren't in the SELECT list. It's valid to do that. But what's curious is that uf there are multiple rows from "cpd" that have different values of "Ort", then there's a pontential to get multiple rows returned, with the same values of "ID_FI", "ID_KP", "Nachname".
What really sticks out though is the outer join to "fpd", and apart from the reference to the "ID_VF" column in the join condition, there aren't any references to columns from "fpd" anywhere else in the query. It seems like if that outer join were removed, we'd get the same result.
The first structural change I would propose would be the removal of the join to "fpd".
SELECT cpd.ID_FI AS firmencode
, cpd.ID_KP AS partnercode
, cpd.Nachname AS Nachname
, MIN(ISNULL( cpd.Vorname ,'')) AS vname
, MIN(CASE cpd.Anrede WHEN 'Frau' THEN 2 ELSE 1 END) AS anrede
, MIN(ISNULL( cpd.EMail ,N'')) AS mail
, MIN(ISNULL( cpd.SAPNr ,N'')) AS sapkunr
, ISNULL( cpd.Titel ,N'') AS titel
FROM dbo.V_CONNECT_ContactPartnerDetail_0010 cpd
JOIN dbo.V_CONNECT_ContactPartnerPivot cpp
ON cpp.ID_C005 = cpd.ID_C005
WHERE cpd.VKO = '0010'
GROUP
BY cpd.ID_FI
, cpd.ID_KP
, cpd.Nachname
, cpd.Ort
, ISNULL( cpd.Titel ,N'')
, cpp.flg_spl
, cpp.flg_ha
, cpp.flg_fu
, cpp.flg_ma
, cpp.flg_ph
We can rearrange the expression in the GROUP BY clause, to move "Title" up with the other columns from "cpd". Without an ORDER BY clause, there's no guarantee what order the rows will be returned in.
We can't tell (from the query, and from the information provided) whether the "ID_C005" column is the PRIMARY KEY or a UNIQUE KEY in either "cpd" or "cpp".
And not knowing that, we can't really make other change to the query without potentially changing the result. If "ID_C005" is unique in "cpp", then we could eliminate all of the "cpp" column references from the GROUP BY.
If the purpose of the inner join (to "cpp") is to filter out rows from "cpd" that don't have a matching row in "cpp", we could make some other changes to the query. And that might make it more "readable".

SELECT Specefic Date in Tsql Query?

I have 3 tables that are joined together with this query.
One of them brings me people names , another one brings me their points and the last one brings me date time.
I select the total people score.
Also, there is a column in the 3th tables that brings me the scores' transaction Date Time. My problem is that I want to write a TSQL query with this condition:
Select the transaction date where the people score is 12,000 or more.
In my idea I should use while loop but I do not know the syntax?
This is how I would do it-
SELECT cp.FirstName
, cp.LastName
, SUM(Points) as Score
FROM ClubProfile cp
RIGHT JOIN CardTransaction ct
ON cp.ClubProfileId = ct.ClubProfileId
INNER JOIN Your3rdTable as t3
ON cp.ClubProfileId = t3.ClubProfileId
WHERE CONVERT(VARCHAR, ct.[Date Column], 101) = #your_date_param
GROUP BY
cp.FirstName
, cp.LastName
HAVING SUM(Points) >=12000
Based on your post this should be close to what you need. You need to add that 3rd table and alter this statement accordingly.
SELECT cp.FirstName
, cp.LastName
, SUM(Points) as Score
FROM [fidilio].[dbo].[ClubProfile] cp
RIGHT JOIN (
CardTransaction ct
INNER JOIN CardTransactionLog ctl
ON cp.CardTransactionLogId = ctl.CardTransactionLogId
)
ON cp.ClubProfileId = ct.ClubProfileId
GROUP BY
cp.FirstName
, cp.LastName
HAVING SUM(Points) >=12000
AND ctl.TransactionTimeStamp = #SomeDateTimeVariable
The variable #SomeDateTimeVariable has to come from someplace what is your exact time-frame criteria

Resources