I have the following data
CREATE TABLE #Test
(
Severity NVARCHAR(50)
,WorkId INT
)
INSERT INTO #Test VALUES('High',1)
INSERT INTO #Test VALUES('Critical',2)
SELECT
CASE
WHEN Severity IN ('High','Critical') THEN 'Critical'
WHEN Severity IN ('Low','Medium') THEN 'Medium'
END AS 'Severity'
,COUNT(*) AS 'Total'
FROM #Test
GROUP BY
CASE
WHEN Severity IN ('High','Critical') THEN 'Critical'
WHEN Severity IN ('Low','Medium') THEN 'Medium'
END
This results in output -
Severity | Total
---------+-------
Critical | 2
I am expecting the following output -
Severity | Total
---------+-------
Critical | 2
Medium | 0
I have looked into the following two links which details a similar case but not same and am still unable to get the result -
http://ask.sqlservercentral.com/questions/47705/showing-null-values-as-well-in-group-by-in-sql.html
How to return empty groups in SQL GROUP BY clause
Any help or links?
Further update.
Having tried the solution below, the results are still not appearing. Pasting here the actual code wherein I would need to apply the logic
SELECT s.NewSeverity AS 'Severity'
,COUNT(WI.microsoft_vsts_common_severity) AS 'Total'
FROM ( VALUES
('Critical','I-High')
,('High','I-High')
,('Medium','I-Low')
,('Low','I-Low')
)s(OldSeverity,NewSeverity)
LEFT JOIN DimWorkItem WI (NOLOCK)
ON WI.microsoft_vsts_common_severity = s.OldSeverity
JOIN dbo.DimPerson P
ON p.personsk = WI.system_assignedto__personsk
JOIN DimTeamProject TP
ON WI.TeamProjectSK = TP.ProjectNodeSK
JOIN DimIteration Itr (NOLOCK)
ON Itr.IterationSK = WI.IterationSK
JOIN DimArea Ar (NOLOCK)
ON Ar.AreaSK = WI.AreaSK
WHERE TP.ProjectNodeName = 'ABC'
AND WI.System_WorkItemType = 'Bug'
AND WI.Microsoft_VSTS_CMMI_RootCause <> 'Change Request'
AND Itr.IterationPath LIKE '%\ABC\R1234\Test\IT%'
AND WI.System_State NOT IN ( 'Rejected', 'Closed' )
AND WI.System_RevisedDate = CONVERT(datetime, '9999', 126)
GROUP BY s.NewSeverity
In actual there are only two 'Low' items, hence the output I am getting is I-Low, 2 whereas I want even I-High to appear with 0 count.
The way I would go about this is to create your own table of values using a table value constructor:
SELECT OldSeverity, NewSeverity
FROM (VALUES
('Critical', 'Critical'),
('High', 'Critical'),
('Medium', 'Medium'),
('Low', 'Medium')
) s (OldSeverity, NewSeverity);
This gives a table you can select from, then left join to your existing table:
SELECT Severity = s.NewSeverity,
Total = COUNT(t.Severity)
FROM (VALUES
('Critical', 'Critical'),
('High', 'Critical'),
('Medium', 'Medium'),
('Low', 'Medium')
) s (OldSeverity, NewSeverity)
LEFT JOIN #Test t
ON t.Severity = s.OldSeverity
GROUP BY s.NewSeverity;
This will give the desired results.
Example on SQL Fiddle
EDIT
The problem you have with the way that you are implimenting the query, is that although you have immediately left joined to DimWorkItem you then inner join to subsequent tables and refer to columns in WorkItem in the where clause, which undoes your left join and turns it back into an inner join. You need to place your whole logic into a subquery, and left join to this:
SELECT s.NewSeverity AS 'Severity'
,COUNT(WI.microsoft_vsts_common_severity) AS 'Total'
FROM ( VALUES
('Critical','I-High')
,('High','I-High')
,('Medium','I-Low')
,('Low','I-Low')
)s(OldSeverity,NewSeverity)
LEFT JOIN
( SELECT wi.Severity
FROM DimWorkItem WI (NOLOCK)
JOIN dbo.DimPerson P
ON p.personsk = WI.system_assignedto__personsk
JOIN DimTeamProject TP
ON WI.TeamProjectSK = TP.ProjectNodeSK
JOIN DimIteration Itr (NOLOCK)
ON Itr.IterationSK = WI.IterationSK
JOIN DimArea Ar (NOLOCK)
ON Ar.AreaSK = WI.AreaSK
WHERE TP.ProjectNodeName = 'ABC'
AND WI.System_WorkItemType = 'Bug'
AND WI.Microsoft_VSTS_CMMI_RootCause <> 'Change Request'
AND Itr.IterationPath LIKE '%\ABC\R1234\Test\IT%'
AND WI.System_State NOT IN ( 'Rejected', 'Closed' )
AND WI.System_RevisedDate = CONVERT(datetime, '9999', 126)
) WI
ON WI.Severity = s.OldSeverity
GROUP BY s.NewSeverity;
Related
I'm using a vendor supplied Relay Database (Aspen), which is running on MS SQL server). I'm attempting to write a pivot query that needs to pivot on 2 columns.
I created a temp table since the data is across multiple tables.
WITH TEMP_TABLE AS (
SELECT
R.LOCATIONID LLOCATIONID, R.ID RID, s.groupname SGROUPNAME,t.settingname TSETTINGNAME, s.setting SSETTING
from tsetting1 s
inner join tsettype1 t on t.relaytype=s.relaytype and t.groupname = s.groupname and t.rownumber = s.rownumber
INNER JOIN TREQUEST Q ON S.REQUESTID = Q.ID
INNER JOIN TRELAY R ON R.ID = Q.RELAYID
INNER JOIN TLOCATION L ON L.ID = R.LOCATIONID
where s.requestid=29117
)
select * from TEMP_TABLE
That select all from Temp returns 38 rows of data, a subset is shown here:
RID -----SGROUPNAME------TSETTINGNAME-------SSETTING
31297 LOAD1 ENABLE TRUE
31297 LOAD1 ANGLE 60
31297 LOAD2 CALCULATED_LOAD 12269
ETC....
I added this pivot, which gets me close:
PIVOT (MAX(SSETTING) FOR TSETTINGNAME IN (ENABLE, REACH, ANGLE, CALCULATED_LOADABILITY, ZLE, CTR, PTR, KVNOM, PICKUP, PERCENTAGE)) P
Returned result from Pivot:
RID-----SGROUPNAME-----ENABLE----REACH----ANGLE----CALCULATED_LOADABILITY
31297 LOAD1 TRUE 15 60 9444
31297 LOAD2 TRUE 10 30 12269
31297 LOAD3 TRUE 20 60 14167
ETC...
I would like to have the data as 1 record for RID 31297, where LOAD1-ENABLE, LOAD2-ENABLE, LOAD3-ENABLE, LOAD1-REACH, ETC. are all headers.
I've tried multiple pivots and cross apply, but I can't seem to get the data to display correctly.
Let me know if anything is unclear or if you need more information. Any help will be greatly appreciated.
Thanks,
Joe C.
It may be easier with a bunch of case statements and a group by RID. By the way this is the "original" method of pivoting before PIVOT was implemented.
select RID
, Load1_Enable = MAX(case when SGROUPNAME = 'Load1' then enable else null end)
, Load2_Enable = MAX(case when SGROUPNAME = 'Load2' then enable else null end)
from [YourTable]
group by RID
I would go all the way to the first cte though:
WITH TEMP_TABLE AS (
SELECT
R.LOCATIONID LLOCATIONID, R.ID RID, s.groupname SGROUPNAME,t.settingname TSETTINGNAME, s.setting SSETTING
from tsetting1 s
inner join tsettype1 t on t.relaytype=s.relaytype and t.groupname = s.groupname and t.rownumber = s.rownumber
INNER JOIN TREQUEST Q ON S.REQUESTID = Q.ID
INNER JOIN TRELAY R ON R.ID = Q.RELAYID
INNER JOIN TLOCATION L ON L.ID = R.LOCATIONID
where s.requestid=29117
)
select RID
,Load1_Enable = MAX(case when SGROUPNAME = 'Load1' and TSETTINGNAME = 'Enable' then SSETTING else null end)
from TEMP_TABLE
group by RID
Note MAX is only there for an aggregate -- you should be aggregating only one record.
I have this QA logic that looks for errors into every AuditID within a RoomID to see if their AuditType were never marked Complete or if they have two complete statuses. Finally, it picks only the maximum AuditDate of the RoomIDs with errors to avoid showing multiple instances of the same RoomID, since there are many audits per room.
The issue is that the AUDIT table is very large and takes a long time to run. I was wondering if there is anyway to reach the same result faster.
Thank you in advance !
IF object_ID('tempdb..#AUDIT') is not null drop table #AUDIT
IF object_ID('tempdb..#ROOMS') is not null drop table #ROOMS
IF object_ID('tempdb..#COMPLETE') is not null drop table #COMPLETE
IF object_ID('tempdb..#FINALE') is not null drop table #FINALE
SELECT distinct
oc.HotelID, o.RoomID
INTO #ROOMS
FROM dbo.[rooms] o
LEFT OUTER JOIN dbo.[hotels] oc on o.HotelID = oc.HotelID
WHERE
o.[status] = '2'
AND o.orderType = '2'
SELECT
t.AuditID, t.RoomID, t.AuditDate, t.AuditType
INTO
#AUDIT
FROM
[dbo].[AUDIT] t
WHERE
t.RoomID IN (SELECT RoomID FROM #ROOMS)
SELECT
t1.RoomID, t3.AuditType, t3.AuditDate, t3.AuditID, t1.CompleteStatus
INTO
#COMPLETE
FROM
(SELECT
RoomID,
SUM(CASE WHEN AuditType = 'Complete' THEN 1 ELSE 0 END) AS CompleteStatus
FROM
#AUDIT
GROUP BY
RoomID) t1
INNER JOIN
#AUDIT t3 ON t1.RoomID = t3.RoomID
WHERE
t1.CompleteStatus = 0
OR t1.CompleteStatus > 1
SELECT
o.HotelID, o.RoomID,
a.AuditID, a.RoomID, a.AuditDate, a.AuditType, a.CompleteStatus,
c.ClientNum
INTO
#FINALE
FROM
#ROOMS O
LEFT OUTER JOIN
#COMPLETE a on o.RoomID = a.RoomID
LEFT OUTER JOIN
[dbo].[clients] c on o.clientNum = c.clientNum
SELECT
t.*,
Complete_Error_Status = CASE WHEN t.CompleteStatus = 0
THEN 'Not Complete'
WHEN t.CompleteStatus > 1
THEN 'Complete More Than Once'
END
FROM
#FINALE t
INNER JOIN
(SELECT
RoomID, MAX(AuditDate) AS MaxDate
FROM
#FINALE
GROUP BY
RoomID) tm ON t.RoomID = tm.RoomID AND t.AuditDate = tm.MaxDate
One section you could improve would be this one. See the inline comments.
SELECT
t1.RoomID, t3.AuditType, t3.AuditDate, t3.AuditID, t1.CompleteStatus
INTO
#COMPLETE
FROM
(SELECT
RoomID,
COUNT(1) AS CompleteStatus
-- Use the above along with the WHERE clause below
-- so that you are aggregating fewer records and
-- avoiding a CASE statement. Remove this next line.
--SUM(CASE WHEN AuditType = 'Complete' THEN 1 ELSE 0 END) AS CompleteStatus
FROM
#AUDIT
WHERE
AuditType = 'Complete'
GROUP BY
RoomID) t1
INNER JOIN
#AUDIT t3 ON t1.RoomID = t3.RoomID
WHERE
t1.CompleteStatus = 0
OR t1.CompleteStatus > 1
Just a thought. Streamline your code and your solution. you are not effectively filtering your datasets smaller so you continue to query the entire tables which is taking a lot of your resources and your temp tables are becoming full copies of those columns without the indexes (PK, FK, ++??) on the original table to take advantage of. This by no means is a perfect solution but it is an idea of how you can consolidate your logic and reduce your overall data set. Give it a try and see if it performs better for you.
Note this will return the last audit record for any room that has either not had an audit completed or completed more than once.
;WITH cte AS (
SELECT
o.RoomId
,o.clientNum
,a.AuditId
,a.AuditDate
,a.AuditType
,NumOfAuditsComplete = SUM(CASE WHEN a.AuditType = 'Complete' THEN 1 ELSE 0 END) OVER (PARTITION BY o.RoomId)
,RowNum = ROW_NUMBER() OVER (PARTITION BY o.RoomId ORDER BY a.AuditDate DESC)
FROm
dbo.Rooms o
LEFT JOIN dbo.Audit a
ON o.RoomId = a.RoomId
WHERE
o.[Status] = 2
AND o.OrderType = 2
)
SELECT
oc.HotelId
,cte.RoomId
,cte.AuditId
,cte.AuditDate
,cte.AuditType
,cte.NumOfAuditsComplete
,cte.clientNum
,Complete_Error_Status = CASE WHEN cte.NumOfAuditsComplete > 1 THEN 'Complete More Than Once' ELSE 'Not Complete' END
FROM
cte
LEFT JOIN dbo.Hotels oc
ON cte.HotelId = oc.HotelId
LEFT JOIN dbo.clients c
ON cte.clientNum = c.clientNum
WHERE
cte.RowNum = 1
AND cte.NumOfAuditsComplete != 1
Also note I changed your
WHERE
o.[status] = '2'
AND o.orderType = '2'
TO
WHERE
o.[status] = 2
AND o.orderType = 2
to be numeric without the single quotes. If the data type is truely varchar add them back but when you query a numeric column as a varchar it will do data conversion and may not take advantage of indexes that you have built on the table.
I have a query which I need to transpose the rows returned into separate columns, but I need the column names returned from the row values, and another field as the value under these columns.
Ultimately this will be going into Excel. I initially thought I could do it with a pivot, but the values field cannot accept text without some work, and there are too many "film right types" to work with. I know the specific rights type currently, but the right descriptions and number of rights may change in the future, so I want it to be as flexible as possible.
I want to group by producer, film and country, with the "Film Right Type" as the columns going across, and the "Availability" as the value for the right type column.
My query as it stands.
Select product_detail.pd_product_code as 'ProductCode',
product_analysis.pa_m_9 as 'Producer',
product_detail.pd_abbv_description as 'Film',
product_detail.pd_commodity_code as 'Country',
variant_analysis.vaa_c_10 as 'Film Right Type',
case when isnull(variant_analysis.vaa_l_1,0) = 0 then 'Non-Exclusive'
Else
case when dateadd(day,datediff(DAY,0,isnull(orders.LastDate,getdate())),0) > dateadd(day,datediff(DAY,0,getdate()),0)
Then 'Available On '+convert(varchar(10),Orders.LastDate, 103)
Else 'Available'
End
end as 'Availability'
From product_detail
join variant_detail on variant_detail.vad_pd_id = product_detail.pd_id
left join variant_analysis on variant_analysis.vaa_vad_id = variant_Detail.vad_id
left join product_analysis on product_analysis.pa_pd_id = product_detail.pd_id
join (select count(variant_detail.vad_id) as CountVariants, variant_Detail.vad_pd_id from variant_Detail group by variant_detail.vad_pd_id) as Variants on Variants.vad_pd_id = product_detail.pd_id
Outer Apply
(select top 1
customer_detail.cd_statement_name as Customer,
order_header_analysis.oha_d_2 as LastDate,
system_order_type.sot_description as OrderType,
order_header.oh_order_number as OrderNo
from order_header
join customer_detail on customer_detail.cd_id = order_header.oh_cd_id
join order_line_item on order_line_item.oli_oh_id = order_header.oh_id
join system_order_type on system_order_type.sot_id = order_header.oh_sot_id
left join order_header_analysis on order_header_analysis.oha_oh_id = order_header.oh_id
where order_header_analysis.oha_d_2 >= getdate()
and order_header.oh_sot_id in (1, 2, 3)
and order_line_item.oli_vad_id = variant_detail.vad_id
ORder By order_header_analysis.oha_d_2 desc) as Orders
where isnull(variant_analysis.vaa_l_2,0) = 0
This is the data I currently get out of it:
This is how I want the end result.
Edit:
I have nearly got this doing what I want after using a pivot.
My below query gives me exactly what I need:
Select *
From(
Select product_detail.pd_product_code as 'ProductCode',
product_analysis.pa_m_9 as 'Producer',
product_detail.pd_abbv_description as 'Film',
product_detail.pd_commodity_code as 'Country',
variant_analysis.vaa_c_10 as 'FilmRightType',
case when isnull(variant_analysis.vaa_l_1,0) = 0 then 'Non-Exclusive'
Else
case when dateadd(day,datediff(DAY,0,isnull(orders.LastDate,getdate())),0) > dateadd(day,datediff(DAY,0,getdate()),0)
Then 'Available On '+convert(varchar(10),Orders.LastDate, 103)
Else 'Available'
End
end as 'Availability'
From product_detail
join variant_detail on variant_detail.vad_pd_id = product_detail.pd_id
left join variant_analysis on variant_analysis.vaa_vad_id = variant_Detail.vad_id
left join product_analysis on product_analysis.pa_pd_id = product_detail.pd_id
join (select count(variant_detail.vad_id) as CountVariants, variant_Detail.vad_pd_id from variant_Detail group by variant_detail.vad_pd_id) as Variants on Variants.vad_pd_id = product_detail.pd_id
Outer Apply
(select top 1
customer_detail.cd_statement_name as Customer,
order_header_analysis.oha_d_2 as LastDate,
system_order_type.sot_description as OrderType,
order_header.oh_order_number as OrderNo
from order_header
join customer_detail on customer_detail.cd_id = order_header.oh_cd_id
join order_line_item on order_line_item.oli_oh_id = order_header.oh_id
join system_order_type on system_order_type.sot_id = order_header.oh_sot_id
left join order_header_analysis on order_header_analysis.oha_oh_id = order_header.oh_id
where order_header_analysis.oha_d_2 >= getdate()
and order_header.oh_sot_id in (1, 2, 3)
and order_line_item.oli_vad_id = variant_detail.vad_id
ORder By order_header_analysis.oha_d_2 desc) as Orders
where isnull(variant_analysis.vaa_l_2,0) = 0
) as FilmVals
pivot
(
max(Availability)
for FilmRightType in (
[Theatrical], [DVD], [Blu ray], [Free TV], [Pay TV], [Video on Demand Catch Up], [Subscription Video on Demand], [Advertising Video on Demand], [TV On Demand Download to Own], [TV On Demand Download to Rent]
)
) piv;
I want to set the list of RightTypes to be dynamic from the DB.
I've created another query using for XML Path and this returns the data in the correct format:
(Select left(RightType.RightTypesList,len(RightType.RightTypesList)-1) From (Select
(Select
DISTINCT
'['+variant_analysis.vaa_c_10+']'+', '
from variant_analysis
where variant_analysis.vaa_c_10 is not null
order by 1
For XML Path ('')) as RightTypesList) as RightType)
But when I put this in place of the hard coded list, I get the following error:
Msg 102, Level 15, State 1, Line 44
Incorrect syntax near '('.
Msg 102, Level 15, State 1, Line 52
Incorrect syntax near ')'.
Try to use PIVOT operator in SQL
Here is an example
How do I create Stored Procedure on these queries and he output should show which check the anomaly was captured from, along with all the relevant data.
SELECT cm.Cust_id, cm.cust_ref_id4, cm.cust_ref_id3, cm.plan_group, cm.Company_name, cm.Cust_firstname, cm.Cust_lastname
COALESCE(c.pkCustomerID, c2.fkCustomerID, c3.pkCustomerID, c4.pkCustomerID) AS pkCustomerID, c3.CompanyName FROM PRODUCTIONSQL.[SigmaPaTri].[dbo].[CUSTOMER_MASTER] cm
LEFT JOIN PHOENIX.CORE.dbo.Customers AS c ON cust_ref_id4 = c.pkCustomerID AND cm.cust_ref_id3 = c.pkCustomerID AND cm.cust_ref_id3 >= 1000000 AND cm.Cust_firstname + ' ' + cm.Cust_lastname = c.CompanyName
LEFT JOIN PHOENIX.CORE.dbo.Contracts AS c2 ON cm.cust_ref_id3 = c2.ConfirmationNumber
WHERE cm.cust_status IN ('A','P','R','G') AND COALESCE(c.pkCustomerID, c2.fkCustomerID) IS NULL ORDER BY cust_ref_id4;
and
SELECT [pkCustomerID],b.[pkContractID],[pkCustomerTypeID],[CustomerType],b.[ContractType] AS Contractype1,c.[ContractType]
AS Contractype2 FROM [CORE].[dbo].[Customers] a
JOIN [CORE].[dbo].[CustomerTypes] ON [pkCustomerTypeID] = [fkCustomerTypeID]
LEFT JOIN (SELECT [pkContractID],[ContractType],[fkCustomerID] FROM [CORE].[dbo].[Contracts]
JOIN [CORE].[dbo].[ContractTypes] ON [fkContractTypeID] = [pkContractTypeID] WHERE [ContractType] NOT LIKE 'Holdover%')b ON a.pkCustomerID=b.fkCustomerID
LEFT JOIN (SELECT [pkContractID],[fkCustomerID],[ContractType] FROM [CORE].[dbo].[Contracts]
JOIN [CORE].[dbo].[ContractTypes] ON [fkContractTypeID] = [pkContractTypeID] WHERE ContractType LIKE 'Holdover%')c ON b.fkCustomerID=c.fkCustomerID WHERE [CustomerType] IN ('Customer','Former Customer') AND (b.ContractType IS NULL OR c.ContractType IS NULL)
You question is lacking a very important piece of information, the explanation of what you are trying to do. I took a shot in the dark here as a guess to what you might be looking for. BTW, I ran this through a formatter so it was legible.
SELECT 'Found in query1'
,cm.Cust_id
,cm.cust_ref_id4
,cm.cust_ref_id3
,cm.plan_group
,cm.Company_name
,cm.Cust_firstname
,cm.Cust_lastname
,COALESCE(c.pkCustomerID, c2.fkCustomerID, c3.pkCustomerID, c4.pkCustomerID) AS pkCustomerID
,c3.CompanyName
FROM PRODUCTIONSQL.[SigmaPaTri].[dbo].[CUSTOMER_MASTER] cm
LEFT JOIN PHOENIX.CORE.dbo.Customers AS c ON cust_ref_id4 = c.pkCustomerID
AND cm.cust_ref_id3 = c.pkCustomerID
AND cm.cust_ref_id3 >= 1000000
AND cm.Cust_firstname + ' ' + cm.Cust_lastname = c.CompanyName
LEFT JOIN PHOENIX.CORE.dbo.Contracts AS c2 ON cm.cust_ref_id3 = c2.ConfirmationNumber
WHERE cm.cust_status IN (
'A'
,'P'
,'R'
,'G'
)
AND COALESCE(c.pkCustomerID, c2.fkCustomerID) IS NULL
SELECT 'Found in query 2'
,[pkCustomerID]
,b.[pkContractID]
,[pkCustomerTypeID]
,[CustomerType]
,b.[ContractType] AS Contractype1
,c.[ContractType] AS Contractype2
FROM [CORE].[dbo].[Customers] a
INNER JOIN [CORE].[dbo].[CustomerTypes] ON [pkCustomerTypeID] = [fkCustomerTypeID]
LEFT JOIN (
SELECT [pkContractID]
,[ContractType]
,[fkCustomerID]
FROM [CORE].[dbo].[Contracts]
INNER JOIN [CORE].[dbo].[ContractTypes] ON [fkContractTypeID] = [pkContractTypeID]
WHERE [ContractType] NOT LIKE 'Holdover%'
) b ON a.pkCustomerID = b.fkCustomerID
LEFT JOIN (
SELECT [pkContractID]
,[fkCustomerID]
,[ContractType]
FROM [CORE].[dbo].[Contracts]
INNER JOIN [CORE].[dbo].[ContractTypes] ON [fkContractTypeID] = [pkContractTypeID]
WHERE ContractType LIKE 'Holdover%'
) c ON b.fkCustomerID = c.fkCustomerID
WHERE [CustomerType] IN (
'Customer'
,'Former Customer'
)
AND (
b.ContractType IS NULL
OR c.ContractType IS NULL
)
I have the following view below. The second nested select is always returning null when I use the TOP(1) clause, but when I remove this clause it returns the data as expected, just more rows than is needed. Does anyone see anything that would explain this?
SELECT TOP (100) PERCENT
a.ITEMID AS Model
,id.CONFIGID
,id.INVENTSITEID AS SiteId
,id.INVENTSERIALID AS Serial
,it.ITEMNAME AS Description
,CASE WHEN it.DIMGROUPID LIKE '%LR-Y' THEN 'Y'
ELSE 'N'
END AS SerialNumberReqd
,ISNULL(it.PRIMARYVENDORID, N'') AS Vendor
,ISNULL(vt.NAME, N'') AS VendorName
,id.INVENTLOCATIONID AS Warehouse
,id.WMSLOCATIONID AS Bin
,ISNULL(CONVERT(varchar(12), CASE WHEN C.DatePhysical < '1901-01-01'
THEN NULL
ELSE C.DatePhysical
END, 101), N' ') AS DeliveryDate
,CASE WHEN (a.RESERVPHYSICAL > 0
OR C.StatusIssue = 1)
AND c.TransType = 0 THEN C.PONumber
ELSE ''
END AS SoNumber
,'' AS SoDetail
,ISNULL(C.PONumber, N'') AS RefNumber
,ISNULL(CONVERT(varchar(12), CASE WHEN ins.ProdDate < '1901-01-01'
THEN NULL
ELSE ins.PRODDATE
END, 101), N' ') AS DateReceived
,it.STKSTORISGROUPID AS ProdGroup
,ISNULL(CONVERT(varchar(12), CASE WHEN ins.ProdDate < '1901-01-01'
THEN NULL
ELSE ins.PRODDATE
END, 101), N' ') AS ProductionDate
,it.ITEMGROUPID
,it.STKSTORISGROUPID AS MerchandisingGroup
,CASE WHEN a.postedValue = 0
THEN (CASE WHEN D.CostAmtPosted = 0 THEN D.CostAmtPhysical
ELSE D.CostAmtPosted
END)
ELSE a.POSTEDVALUE
END AS Cost
,CASE WHEN a.PHYSICALINVENT = 0 THEN a.Picked
ELSE a.PhysicalInvent
END AS PhysicalOnHand
,ins.STKRUGSQFT AS RugSqFt
,ins.STKRUGVENDSERIAL AS RugVendSerial
,ins.STKRUGVENDDESIGN AS RugVendDesign
,ins.STKRUGEXACTSIZE AS RugExactSize
,ins.STKRUGCOUNTRYOFORIGIN AS RugCountryOfOrigin
,ins.STKRUGQUALITYID AS RugQualityId
,ins.STKRUGCOLORID AS RugColorId
,ins.STKRUGDESIGNID AS RugDesignId
,ins.STKRUGSHAPEID AS RugShapeId
,CASE WHEN (a.AVAILPHYSICAL > 0) THEN 'Available'
WHEN (id.WMSLOCATIONID = 'NIL') THEN 'Nil'
WHEN (a.RESERVPHYSICAL > 0)
AND (c.TransType = 0) THEN 'Committed'
WHEN (a.RESERVPHYSICAL > 0) THEN 'Reserved'
WHEN (id.WMSLOCATIONID LIKE '%-Q') THEN 'Damaged'
WHEN (a.Picked > 0) THEN 'Picked'
ELSE 'UNKNOWN'
END AS Status
,'' AS ReasonCode
,'' AS BaseModel
,ISNULL(CAST(ins.STKSTORISCONFIGINFO AS nvarchar(1000)), N'') AS StorisConfigInfo
,ISNULL(C.ConfigSummary, N'') AS ConfigSummary
FROM
dbo.INVENTSUM AS a WITH (NOLOCK)
INNER JOIN dbo.INVENTDIM AS id WITH (NOLOCK)
ON id.DATAAREAID = a.DATAAREAID
AND id.INVENTDIMID = a.INVENTDIMID
LEFT OUTER JOIN dbo.INVENTTABLE AS it WITH (NOLOCK)
ON it.DATAAREAID = a.DATAAREAID
AND it.ITEMID = a.ITEMID
LEFT OUTER JOIN dbo.VENDTABLE AS vt WITH (NOLOCK)
ON vt.DATAAREAID = it.DATAAREAID
AND vt.ACCOUNTNUM = it.PRIMARYVENDORID
LEFT OUTER JOIN dbo.INVENTSERIAL AS ins WITH (NOLOCK)
ON ins.DATAAREAID = id.DATAAREAID
AND ins.INVENTSERIALID = id.INVENTSERIALID
LEFT OUTER JOIN (SELECT TOP (1)
itt.ITEMID
,invt.INVENTSERIALID
,itt.DATEPHYSICAL AS DatePhysical
,itt.TRANSREFID AS PONumber
,itt.TRANSTYPE AS TransType
,itt.STATUSISSUE AS StatusIssue
,dbo.stkRowsToColumn(itt.INVENTTRANSID, 'STI') AS ConfigSummary
,itt.RECID
FROM
dbo.INVENTTRANS AS itt WITH (NOLOCK)
INNER JOIN dbo.INVENTDIM AS invt WITH (NOLOCK)
ON invt.DATAAREAID = itt.DATAAREAID
AND invt.INVENTDIMID = itt.INVENTDIMID
WHERE
(itt.DATAAREAID = 'STI')
AND (itt.TRANSTYPE IN (0, 2, 3, 8))
AND (invt.INVENTSERIALID <> '')
ORDER BY
itt.RECID DESC) AS C
ON C.ITEMID = a.ITEMID
AND C.INVENTSERIALID = id.INVENTSERIALID
LEFT OUTER JOIN (SELECT TOP (1)
itt2.ITEMID
,invt2.INVENTSERIALID
,itt2.COSTAMOUNTPOSTED AS CostAmtPosted
,itt2.COSTAMOUNTPHYSICAL + itt2.COSTAMOUNTADJUSTMENT AS CostAmtPhysical
,itt2.RECID
FROM
dbo.INVENTTRANS AS itt2 WITH (NOLOCK)
INNER JOIN dbo.INVENTDIM AS invt2 WITH (NOLOCK)
ON invt2.DATAAREAID = itt2.DATAAREAID
AND invt2.INVENTDIMID = itt2.INVENTDIMID
WHERE
(itt2.DATAAREAID = 'STI')
AND (itt2.TRANSTYPE IN (0, 2, 3, 4, 6, 8))
AND (invt2.INVENTSERIALID <> '')
ORDER BY
itt2.RECID DESC) AS D
ON D.ITEMID = a.ITEMID
AND D.INVENTSERIALID = id.INVENTSERIALID
WHERE
(a.DATAAREAID = 'STI')
AND (a.CLOSED = 0)
AND (a.PHYSICALINVENT > 0)
AND (it.ITEMGROUPID LIKE 'FG-%'
OR it.ITEMGROUPID = 'MULTISHIP')
ORDER BY
SiteId
,Warehouse
Presumably, the top value in the subquery doesn't meet the subsequent join conditions. That is, this condition is not met:
D.ITEMID = a.ITEMID AND D.INVENTSERIALID = id.INVENTSERIALID
You are using a left outer join, so NULL values are filled in.
EDIT:
To re-iterate. When you run it with top 1, there are no values (for at least some combinations of the two variables). So, NULL will be filled in for these values. After all, top 1 (with or without the parentheses) returns only one row.
When you run it returning multiple rows, presumably there are matches. For the rows that match, the corresponding values are put it. This is the way that left outer join works.
Gordon's answer is correct as to why I was getting a few rows when removing top and none when I had it. The subquery in question was returning all the rows in the InventTrans table (5 million+) so when I used top, it was just getting the first row which didn't have anything. I realized this was the case when I was trying random high values (e.g 50000) in the TOP clause.
The ultimate fix was to change the left outer joins on the C and D subqueries to Cross Apply, and then change the where clauses to better filter the table (e.g itt.itemid = a.itemid and invt1.inventserialid = id.inventserialid). Using that, I was able to use TOP 1 as expected.