Data show by list when group by is not include data - sql

I have a sql command like this
select mainPOID.EstAPDate,mainPOID.POID,TTm.ID,TTMAmount=TTMD.InvoiceAmount
From TTBeforeMms TTM
inner join TTBeforeMms_Detail TTMD on TTM.ID = TTMD.ID
inner join (
select distinct main.EstAPDate,main_D.POID
From AP main
left join AP_Detail main_D on main.ID = main_D.ID
where main.Type ='PA' and main.EstAPDate between '2018/6/01' AND '2018/6/15' and left(main_D.InvoiceNo,4) != '1111' ) mainPOID on TTMD.poid =mainPOID.POID and TTM.EstAPdate<=mainPOID.EstAPdate and mainPOID.POID='CM3PU18030009'
order by mainPOID.EstAPDate,mainPOID.POID
sql result will like this
My question is
How can Data show by list when group by is not include data?
For example
ID will show by list When I group by EstAPDate、POID and sum(TTMAmount)

You can store in one temp table or use CTE
CREATE TABLE [dbo].#Columnss(
espapdate date ,
poid varchar(max),
id varchar(max),amount decimal(22,6))
GO
insert into #Columnss values('2018-06-15','cm3','pt20',19988.8900)
insert into #Columnss values('2018-06-15','cm3','pt21',265.8900)
SELECT
REPLACE(ESPAPDATE,'-','/') ESPAPDATE, POID,
STUFF(
(SELECT ' , ' + OD.ID
FROM #COLUMNSS OD
WHERE OD.ESPAPDATE = O.ESPAPDATE
AND OD.POID = O.POID
FOR XML PATH('')), 1, 2, ''
) PRODUCTNAMES,SUM(AMOUNT)AMOUNT
FROM #COLUMNSS O
GROUP BY ESPAPDATE, POID
output
espapdate poid ProductNames amount
2018/06/15 cm3 pt20 , pt21 20254.780000

there are lots of CSV example using FOR XML PATH. For your case here, i am wrapping your existing query in a CTE and then from there generate the CSV string for ID
; with
cte as
(
select mainPOID.EstAPDate, mainPOID.POID, TTm.ID, TTMAmount=TTMD.InvoiceAmount
From TTBeforeMms TTM
inner join TTBeforeMms_Detail TTMD on TTM.ID = TTMD.ID
inner join (
select distinct main.EstAPDate,main_D.POID
From AP main
left join AP_Detail main_D on main.ID = main_D.ID
where main.Type ='PA'
and main.EstAPDate between '2018/6/01' AND '2018/6/15'
and left(main_D.InvoiceNo,4) != '1111'
) mainPOID on TTMD.poid = mainPOID.POID
and TTM.EstAPdate <= mainPOID.EstAPdate
and mainPOID.POID = 'CM3PU18030009'
)
SELECT EstAPDate, POID,
ID = STUFF(c.ID, 1, 1, ''),
TTMAmount = SUM(TTMAmount)
FROM cte
CROSS APPLY
(
SELECT ',' + ID
FROM cte x
WHERE x.EstAPDate = cte.EstAPDate
AND x.POID = cte.POID
FOR XML PATH ('')
) c (ID)
GROUP BY EstAPDate, POID
ORDER BY EstAPDate, POID

Related

How do I use a CASE statement in a JOIN in SQL Server?

I have a stored procedure that I want to select a column if the applicationTypeId is in a list of IDs. I am trying to use the CASE statement but I don't know what I am doing wrong. I created a table and added the ApplicationTypeIds to it. The table name is #RelationshipsTypeApplicationId
In other words, what I am trying to do is the following:
If the applicationTypeId is in the #RelationshipsTypeApplicationId table
Join and select the Name column from the IGCRelationshipTypes table
Here is my original stored procedure
WITH AllCustomers AS
(
SELECT
app.ApplicationId,
cust.Name,
ApplicationTypes.TypeName AS ApplicationType,
ApplicationSources.ApplicationSourceName AS ApplicationSource,
CreatedDate = app.CreatedDate,
LastUpdateDate = app.StatusChangeDate,
app.StatusId,
InProgress = STUFF((SELECT ';'+#aw.ApplicationWorkflowName
FROM #aw
WHERE #aw.ApplicationId = app.ApplicationId
ORDER BY StepNumber
FOR XML PATH('')), 1, 1, ''),
ActionRequired = (SELECT top 1 1 FROM #aw
WHERE #aw.ApplicationId = app.ApplicationId
AND #aw.WorkflowStatusId = 6),
AccountId = STUFF((SELECT ';' + acct.AccountId
FROM #accounts AS acct
WHERE acct.ApplicationId = app.ApplicationId
ORDER BY acct.ParentAccountId
FOR XML PATH('')), 1, 1, '')
FROM
[dbo].[Applications] app
INNER JOIN
[dbo].[Customers] AS cust ON cust.CustomerId = app.CustomerId
INNER JOIN
[dbo].[ApplicationTypes] ON ApplicationTypes.ApplicationTypeId = app.ApplicationTypeId
INNER JOIN
[dbo].[ApplicationSources] ON ApplicationSources.ApplicationSourceId = app.ApplicationSourceId
WHERE
app.StatusId <> '4020-8901-64FFE33F06B1'
AND (#applicationTypeId IS NULL OR app.ApplicationTypeId = #applicationTypeId)
And here is what I updated:
WITH AllCustomers AS
(
SELECT
app.ApplicationId,
cust.Name,
ApplicationTypes.TypeName AS ApplicationType,
ApplicationSources.ApplicationSourceName AS ApplicationSource,
CreatedDate = app.CreatedDate,
LastUpdateDate = app.StatusChangeDate,
app.StatusId,
InProgress = STUFF((SELECT ';' + #aw.ApplicationWorkflowName
FROM #aw
WHERE #aw.ApplicationId = app.ApplicationId
ORDER BY StepNumber
FOR XML PATH('')), 1, 1, ''),
ActionRequired = (SELECT top 1 1 FROM #aw
WHERE #aw.ApplicationId = app.ApplicationId
AND #aw.WorkflowStatusId = 6),
AccountId = STUFF((SELECT ';' + acct.AccountId
FROM #accounts as acct
WHERE acct.ApplicationId = app.ApplicationId
ORDER BY acct.ParentAccountId
FOR XML PATH('')), 1, 1, ''),
CASE
WHEN app.ApplicationTypeId IN (SELECT * FROM #RelationshipsTypeApplicationId)
THEN relationshipType.Name
END
FROM
[dbo].[Applications] app
INNER JOIN
[dbo].[Customers] AS cust ON cust.CustomerId = app.CustomerId
INNER JOIN
[dbo].[ApplicationTypes] ON ApplicationTypes.ApplicationTypeId = app.ApplicationTypeId
INNER JOIN
[dbo].[ApplicationSources] ON ApplicationSources.ApplicationSourceId = app.ApplicationSourceId
INNER JOIN
[dbo].[IGCRelationshipTypes] AS relationshipType
ON CASE
WHEN app.ApplicationTypeId IN (SELECT * FROM #RelationshipsTypeApplicationId)
THEN (relationshipType.Name = #relationshipType)
END
WHERE
app.StatusId <> '4020-8901-64FFE33F06B1'
AND (#applicationTypeId IS NULL OR app.ApplicationTypeId = #applicationTypeId)
Here is a screenshot of the syntax error:
Can someone shed some light on what I am missing here?
CASE in T-SQL is an expression that returns a single scalar value, it is not for control of flow. See Dirty secrets of the CASE expression. You'll need something like this, but I don't have the energy to try to determine why you have a table named #RelationshipsTypeApplicationId with a single column (because you really shouldn't say IN (SELECT *)) or if you want to do something different when the match does not exist.
...
ON relationshipType.Name = CASE
WHEN app.ApplicationTypeId IN
(SELECT * FROM #RelationshipsTypeApplicationId)
THEN #relationshipType END
...

Attempting to set a non-NULL- able column's value to NULL

I am getting attempting to set a non-NULL- able column's value to NULL
error when I use FOR XML PATH('')
Code:
select
fdp.POLICYNUMBER,
fdp.INSUREDNAME,
fdp.OWNERNAME,
fdp.AGENCYCODE,
p.WFWORKSTEPNAME,
fdpc.NIGO,
fdpc.NIGOREASON,
d.NIGOREQUIREMENT,
wci.WCSTATUS,
wci.DATECOMPLETED,
fdCI.NEWUNDERWRITINGUSER,
fdr.NBAMOUNT
into
#t
from
PINewBusiness p
join
FDPolicyDetails fdp on SUBSTRING(p.CFREPKEY, 9, LEN(p.CFREPKEY)) = fdp.PARENT_CASEID
and (p.WFWORKSTEPNAME = 'PendingRequirements' or
p.WFWORKSTEPNAME = 'FollowUpRequirements' )
join
FDProcessing fdpc on SUBSTRING(p.CFREPKEY, 9, LEN(p.CFREPKEY)) = fdpc.PARENT_CASEID
join
FDRounting fdr on SUBSTRING(p.CFREPKEY, 9, LEN(p.CFREPKEY)) = fdr.PARENT_CASEID
cross apply
(select NIGOREQUIREMENT + ', '
from FDNIGORequirements nr
where nr.PARENT_CASEID = fdpc.PARENT_CASEID
for xml path('')) D (NIGOREQUIREMENT)
--join FDNIGORequirements nr on SUBSTRING(p.CFREPKEY, 9, LEN(p.CFREPKEY)) = nr.PARENT_CASEID
cross apply
(select NIGOREQUIREMENT + ', '
from FDNIGORequirements nr
where nr.PARENT_CASEID = SUBSTRING(p.CFREPKEY,9,LEN(p.CFREPKEY))
for xml path('')) D (NIGOREQUIREMENT)
join
(select max(CREATEDDATETIME) as CREATEDDATETIME, PARENT_CASEID
from FDWelcomeCall
group by PARENT_CASEID ) wc on fdr.PARENT_CASEID = wc.PARENT_CASEID
join
FDWelcomeCall wci on wci.PARENT_CASEID = wc.PARENT_CASEID
and wci.CREATEDDATETIME = wc.CREATEDDATETIME
join
FDCaseInformation fdCI on SUBSTRING(p.CFREPKEY, 9, LEN(p.CFREPKEY)) = fdCI.PARENT_CASEID
where
p.WFSTEPENTRYTIME >= #sdate
and p.WFSTEPENTRYTIME <= #edate
order by
p.WFFLOWENTRYTIME desc
If you want to keep the rows with NULL values you must replace the nulls in the column that gives you the error, to do so you can use:
SELECT COALESCE([MyColumn],__ReplacementValue__) AS [MyColumn] FROM MyTable
or
SELECT ISNULL([MyColumn],__ReplacementValue__) AS [MyColumn] FROM MyTable
You can use one of them in the inner or outer SELECT.
Otherwise, if the row should not exist if that value is null you must filter it out by adding a WHERE clause:
WHERE [MyColumn] IS NOT NULL

Using FOR XML to group against 2 sql tables

I have a sql query below, that I would like to format as XML using the FOR XML syntax.
SELECT
gr.id,
gr.created,
ts.ordernumber
FROM trGrouped gr
INNER JOIN transactions ts
ON ts.grouped_id = gr.id
WHERE ts.ordernumber IN ('4003970100000383', '4003970100000376', '4003970100000369', '1022108100000018')
This is an example of the XML format I would like the query to look like.
<trans_groups>
<grouped id="56" created="4/14/2017">
<ordernumber>1022108100000001</ordernumber>
<ordernumber>1022108100000002</ordernumber>
<ordernumber>1022108100000003</ordernumber>
</grouped>
<grouped id="57" created="4/14/2017">
<ordernumber>1022109100000001</ordernumber>
<ordernumber>1022109100000002</ordernumber>
</grouped>
</trans_groups>
So far I have not been able to get this quite right. I have tried the following but this is not grouping the orders.
select gr.id as [#id], gr.created as [#created],
(
SELECT ts.ordernumber as ordernumber
)
FROM trGrouped gr inner join transactions ts on ts.grouped_id = gr.id
where ts.ordernumber in('4003970100000383', '4003970100000376', '4003970100000369', '1022108100000018')
FOR XML PATH('grouped'), ROOT('trans_groups')
Here is one approach
Example
Declare #YourTable table (id int,created date, ordernumber varchar(25))
Insert Into #YourTable values
(56,'04/14/2017','1022108100000001')
,(56,'04/14/2017','1022108100000002')
,(56,'04/14/2017','1022108100000003')
,(57,'04/14/2017','1022109100000001')
,(57,'04/14/2017','1022109100000002')
Select [#id] = id
,[#created] = convert(VARCHAR(10), created, 101)
,(
Select ordernumber
From #YourTable A1
Where A1.id = A.id
For XML Path(''), type
)
From (Select Distinct ID,Created From #YourTable ) A
For XML Path('grouped'), Root('trans_groups')
Returns
<trans_groups>
<grouped id="56" created="04/14/2017">
<ordernumber>1022108100000001</ordernumber>
<ordernumber>1022108100000002</ordernumber>
<ordernumber>1022108100000003</ordernumber>
</grouped>
<grouped id="57" created="04/14/2017">
<ordernumber>1022109100000001</ordernumber>
<ordernumber>1022109100000002</ordernumber>
</grouped>
</trans_groups>
This is working for me.
select gr.id as [#id], gr.created as [#created],
(
SELECT ordernumber as ordernumber from transactions where grouped_id = grouped_id
and ordernumber in ('4003970100000383', '4003970100000376', '4003970100000369', '1022108100000018')
FOR XML path(''), type
)
FROM (SELECT distinct gr.id, created FROM trGrouped gr inner join transactions ts on ts.grouped_id = gr.id
where ts.ordernumber in('4003970100000383', '4003970100000376', '4003970100000369', '1022108100000018')) gr
FOR XML PATH('grouped'), ROOT('trans_groups')

Optimize SQL Server query for speed

How can I optimize my SQL Server query ? Here is the code that I want to optimize
CREATE TABLE #Temp
(
TransactionId int PRIMARY KEY,
TransactionStepId int
)
INSERT INTO #Temp(TransactionId, TransactionStepId)
SELECT
TransactionId, MAX(TransactionStepId) TransactionStepId
FROM
[WarehouseMgmt].[FactPaymentTrans] FPT
JOIN
WarehouseMgmt.DimTimeZone DTZ on FPT.[TimeId] = DTZ.TimeUTCId
WHERE
FactType = 'SOURCE'
AND (DTZ.TimeId BETWEEN #DimStartDate AND #DimEndDate)
GROUP BY
TransactionId
IF(UPPER(#ReportBy) = 'TRANSACTION')
BEGIN
SET #sql = '
INSERT INTO #Results (
[PaymentTypeId],
[TransactionDate],
[PaymentMethodId],
[3DSecureId],
[ProductId],
[ProductTypeId],
[TransactionStatusId],
[Amount],
[Currency],
[PlayerId],
[PlayerSourceOrigId],
[Username],
[FirstName],
[LastName],
[BrandId],
[VIPLevelId],
[MarketingChannelId],
[MarketingSourceId],
[CommentId],
[CommentRefId],
[AdminName],
[OriginalTransactionId],
[TransactionId],
[RelatedTransactionId],
[ProviderTransactionOrigId]
)
SELECT
DTST.[Id],
FPT.[StartTime],
FPT.[PaymentMethodId],
FPT.[3DSecureId],
FPT.[ProductId],
DPT.[Id],
FPT.[TransactionStatusId],
FPT.[Amount],
FPT.CurrencyId,
FPT.[PlayerId],
DPL.[SourceOrigId],
DPL.[Username],
DPL.[FirstName],
DPL.[LastName],
DPL.[BrandId],
DPL.[VIPLevelId],
DPL.[MarketingChannelId],
DPL.[MarketingSourceId],
FPT.[PaymentReasonTextId],
FPT_Ref.[PaymentReasonTextId],
FPT.CreatedByAdminId,
FPT.[OriginalTransactionId],
FPT.[TransactionId],
FPT_Ref.[OriginalTransactionId],
FPT.[ProviderTransactionOrigId]
FROM WarehouseMgmt.FactPaymentTrans AS FPT
JOIN #Temp T ON FPT.TransactionId = T.TransactionId AND FPT.TransactionStepId = T.TransactionStepId
JOIN WarehouseMgmt.DimTransactionStepType AS DTST ON FPT.[TransactionStepTypeId] = DTST.[Id]
JOIN WarehouseMgmt.DimPlayer AS DPL ON FPT.PlayerId = DPL.Id
JOIN WarehouseMgmt.DimProduct AS DP ON DP.Id = FPT.ProductId
JOIN WarehouseMgmt.DimProductType AS DPT ON DPT.Id = DP.ProductTypeId
--JOIN WarehouseMgmt.DimTimeZone DTZ on FPT.[TimeId] = DTZ.TimeUTCId
JOIN [WarehouseMgmt].[DimLoyaltyProgramLevel] DLPL ON DLPL.[Id]=DPL.VipLevelId
LEFT JOIN
(
SELECT FPT_Ref_1.TransactionId,FPT_Ref_1.FactType,FPT_Ref_1.OriginalTransactionId,FPT_Ref_1.[PaymentReasonTextId]
FROM WarehouseMgmt.FactPaymentTrans AS FPT_Ref_1
JOIN #Temp T ON T.TransactionId = FPT_Ref_1.OriginalTransactionId AND T.TransactionStepId = FPT_Ref_1.TransactionStepId
) AS FPT_Ref ON FPT_Ref.OriginalTransactionId = FPT.TransactionId AND FPT_Ref.FactType = ''SOURCE''
WHERE (FPT.FactType = ''SOURCE'') ' + #sqlFilters
I tried to put this
SELECT TransactionId,MAX(TransactionStepId) TransactionStepId
FROM [WarehouseMgmt].[FactPaymentTrans]
WHERE FactType = ''SOURCE''
GROUP BY TransactionId
in a temp table, but this is even worst that without temp table. I want to select latest TransactionId(thats made by MAX(TransactionStepId) and also to select last TransactionId in the left JOIN
My execution plan is:
Have you considered using ROW_NUMBER instead of joining your table twice? Please try this:
;WITH FactPaymentTrans_Last
AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY TransactionID ORDER BY TransactionStepID DESC) AS RN
FROM WarehouseMgmt.FactPaymentTrans
)
SELECT DTST.[Id]
, FPT.[StartTime]
, FPT.[PaymentMethodId]
, FPT.[3DSecureId]
, FPT.[ProductId]
, DPT.[Id]
, FPT.[TransactionStatusId]
, FPT.[Amount]
, FPT.CurrencyId
, FPT.[PlayerId]
, DPL.[SourceOrigId]
, DPL.[Username]
, DPL.[FirstName]
, DPL.[LastName]
, DPL.[BrandId]
, DPL.[VIPLevelId]
, DPL.[MarketingChannelId]
, DPL.[MarketingSourceId]
, FPT.[PaymentReasonTextId]
, FPT_Ref.[PaymentReasonTextId]
, FPT.CreatedByAdminId
, FPT.[OriginalTransactionId]
, FPT.[TransactionId]
, FPT_Ref.[OriginalTransactionId]
, FPT.[ProviderTransactionOrigId]
FROM FactPaymentTrans_Last AS FPT
INNER JOIN WarehouseMgmt.DimTransactionStepType AS DTST
ON FPT.[TransactionStepTypeId] = DTST.[Id]
INNER JOIN WarehouseMgmt.DimPlayer AS DPL
ON FPT.PlayerId = DPL.Id
INNER JOIN WarehouseMgmt.DimProduct AS DP
ON DP.Id = FPT.ProductId
WHERE FPT.RN = 1;
It's just a snippet to give you idea how you can use this to get latest TransactionIds based on its TransactionStepId.
If it's not enough - please post these:
Your table structure
Indices on them
Your execution plan
It will help to give you suggestions.
There are multiple factors which can improve query performance and one of them which can be done, without necessarily knowing details about indexes, database schema, data distribution etc. is the order of the JOINs in the query.
I have refactored your query and I think you should get the same result as before, but with an improved execution time:
SELECT DTST.[Id]
,FPT.[StartTime]
,FPT.[PaymentMethodId]
,FPT.[3DSecureId]
,FPT.[ProductId]
,DPT.[Id]
,FPT.[TransactionStatusId]
,FPT.[Amount]
,FPT.CurrencyId
,FPT.[PlayerId]
,DPL.[SourceOrigId]
,DPL.[Username]
,DPL.[FirstName]
,DPL.[LastName]
,DPL.[BrandId]
,DPL.[VIPLevelId]
,DPL.[MarketingChannelId]
,DPL.[MarketingSourceId]
,FPT.[PaymentReasonTextId]
,FPT_Ref.[PaymentReasonTextId]
,FPT.CreatedByAdminId
,FPT.[OriginalTransactionId]
,FPT.[TransactionId]
,FPT_Ref.[OriginalTransactionId]
,FPT.[ProviderTransactionOrigId]
FROM WarehouseMgmt.FactPaymentTrans AS FPT
INNER JOIN WarehouseMgmt.DimPlayer AS DPL
ON FPT.PlayerId = DPL.Id
INNER JOIN WarehouseMgmt.DimProduct AS DP
ON DP.Id = FPT.ProductId
INNER JOIN WarehouseMgmt.DimProductType AS DPT
ON DPT.Id = DP.ProductTypeId
INNER JOIN WarehouseMgmt.DimTransactionStepType AS DTST
ON FPT.[TransactionStepTypeId] = DTST.[Id]
WHERE (FPT.FactType = '' SOURCE '')
AND EXISTS (SELECT 1
FROM [WarehouseMgmt].[FactPaymentTrans]
WHERE FactType = '' SOURCE ''
AND FPT.TransactionId = TransactionId
AND FPT.TransactionStepId = TransactionStepId)
AND EXISTS (SELECT 1
FROM [WarehouseMgmt].[DimLoyaltyProgramLevel] DLPL
WHERE DLPL.[Id] = DPL.VipLevelId)
AND EXISTS (SELECT 1
FROM WarehouseMgmt.DimTimeZone DTZ
WHERE FPT.[TimeId] = DTZ.TimeUTCId
AND DTZ.TimeId BETWEEN #DimStartDate AND #DimEndDate)

SQL INNER JOIN DISTINCT with max function

I have the tables tbMeasurement and tbPatientMeasurement .
tbMeasurement
MeasurementIDP
MeasurementName
tbPatientMeasurement
PatientMeasurementIDP
MeasurementIDF
MeasurementValue
Taken (Datetime)
When doing the following query:
SELECT DISTINCT dbo.tbMeasurement.MeasurementName
, dbo.tbPatientMeasurement.MeasurementValue
, dbo.tbPatientMeasurement.Taken
FROM dbo.tbMeasurement
INNER JOIN dbo.tbPatientMeasurement
ON dbo.tbMeasurement.MeasurementIDP = dbo.tbPatientMeasurement.MeasurementIDF
This returns a double entry of one of the MeasurementName.
and i also want MeasurementName,MeasurementValue by max Taken(datetime).
Try this one -
SELECT DISTINCT
m.MeasurementName
, p2.MeasurementValue
, p2.Taken
FROM dbo.tbMeasurement m
JOIN (
SELECT
p.MeasurementValue
, Taken = MAX(p.Taken)
FROM dbo.tbPatientMeasurement p
GROUP BY m.MeasurementName, p.MeasurementValue
) p2 ON m.MeasurementIDP = p2.MeasurementIDF
SELECT
m.MeasurementName
, p.MeasurementValue
, a.Taken
FROM dbo.tbMeasurement m
INNER JOIN dbo.tbPatientMeasurement p ON m.MeasurementIDP = p.MeasurementIDF
INNER JOIN
(
select MeasurementIDF,MAX(Taken) as taken
from tbPatientMeasurement
group by MeasurementIDF
) a on a.MeasurementIDF=p.MeasurementIDF and a.taken=p.Taken