SQL Subquery with a COUNT - sql-server

I have a table of our communications containing; Created User, Created Date & Sub Code. I want the output to have 4 columns in SSRS, showing communications from the previous month;
Comms logged Dealt With % Dealt With
Created User 1
Created User 2
So far I've got;
SELECT
[EM-COMMUNICATION].[CRT-USER]
,COUNT([EM-COMMUNICATION].[CRT-USER]) AS LOGGED
,(SELECT COUNT([EM-COMMUNICATION].[CRT-USER]) FROM [EM-COMMUNICATION] WHERE [EM-COMMUNICATION].[SUB-CODE] = N'DEALTWITH' AND DateDiff(MONTH,[EM-COMMUNICATION].[CRT-DATE],GetDate()) = 1) AS Dealt
FROM
[EM-COMMUNICATION]
WHERE
DateDiff(MONTH,[EM-COMMUNICATION].[CRT-DATE],GetDate()) = 1
GROUP BY
[EM-COMMUNICATION].[CRT-USER]
The problem I'm having is that the sub query is returning a count of comms for all users, instead of matching the groupings of the main query, i.e., each row has the same count in 'Dealt With'

You need to relate your subquery with your main query using AND [EM-COMMUNICATION].[CRT-USER] = T.[CRT-USER]
SELECT
[EM-COMMUNICATION].[CRT-USER]
,COUNT([EM-COMMUNICATION].[CRT-USER]) AS LOGGED
,(SELECT COUNT([EM-COMMUNICATION].[CRT-USER]) FROM [EM-COMMUNICATION] as T WHERE T.[SUB-CODE] = N'DEALTWITH' AND DateDiff(MONTH,T.[CRT-DATE],GetDate()) = 1 AND [EM-COMMUNICATION].[CRT-USER] = T.[CRT-USER]) AS Dealt
FROM
[EM-COMMUNICATION]
WHERE
DateDiff(MONTH,[EM-COMMUNICATION].[CRT-DATE],GetDate()) = 1
GROUP BY
[EM-COMMUNICATION].[CRT-USER]

Related

Microsoft SQL Server: wrong query execution plan taking too long

This is on Windows SQL Server Cluster.
Query is coming from 3rd party application so I can not modify the query permanently.
Query is:
DECLARE #FromBrCode INT = 1001
DECLARE #ToBrCode INT = 1637
DECLARE #Cdate DATE = '31-mar-2017'
SELECT
a.PrdCd, a.Name, SUM(b.Balance4) as Balance
FROM
D009021 a, D010014 b
WHERE
a.PrdCd = LTRIM(RTRIM(SUBSTRING(b.PrdAcctId, 1, 8)))
AND substring(b.PrdAcctId, 9, 24) = '000000000000000000000000'
AND a.LBrCode = b.LBrCode
AND a.LBrCode BETWEEN #FromBrCode AND #ToBrCode
AND b.CblDate = (SELECT MAX(c.CblDate)
FROM D010014 c
WHERE c.PrdAcctId = b.PrdAcctId
AND c.LBrCode = b.LBrCode
AND c.CblDate <= #Cdate)
GROUP BY
a.PrdCd, a.Name
HAVING
SUM(b.Balance4) <> 0
ORDER BY
a.PrdCd
This particular query is taking too much time to complete execution. The same problem happens on a different SQL Server.
No table lock was found, processor and memory usage is normal while the query is running.
Normal "select top 1000" working and showing output instantly in both tables (D009021, D010014)
Reindex and rebuild / update stats done in both tables but problem did not resolve (D009021, D010014)
The same query is working if we reduce number of branch but slowly
(
DECLARE #FromBrCode INT =1001
DECLARE #ToBrCode INT =1001
)
The same query is working faster giving output within 2 mins if we replace any one variable and use the value directly
AND a.LBrCode BETWEEN #FromBrCode AND #ToBrCode
changed to
AND a.LBrCode BETWEEN 1001 AND #ToBrCode
The same query is working faster and giving output within 2 mins if we add "OPTION (RECOMPILE)" at end
I tried to clean cache query execution plan and optimized new one but problem still exists
Found that the query estimate plan and actual execution plan are different (see screenshots)
Table D010014 is aliased twice once as b and once as c
the they are joined to the same table.
Try toto remove the sub query below and create a temp table to store
the values you need. I added * to the fields you self join
SELECT MAX(c.CblDate)
FROM D010014 c
WHERE c.PrdAcctId = b.PrdAcctId
AND c.LBrCode = b.LBrCode
AND c.CblDate <= #Cdate
if you cant do that then try
SELECT TOP 1 c.CblDate
FROM D010014 c
WHERE c.PrdAcctId = b.PrdAcctId
AND c.LBrCode = b.LBrCode
AND c.CblDate <= #Cdate
ORDER BY c.CblDate DESC

how to for each loop on data table within another datatable

I have a web poll application that reads and processes orders from sql server back end and inserts into windss(jda).
the flow
1) I read all the orders from the sql server tables that is not processed
2) then I need to divide the orders into two sets
- set 1 orders with bundle kit( 1 order with several suborders)
- set 2 is just orders with no bundle kit
3) then after each order is processed I need to update the isprocessed sql field to 1
1) code for reading all orders
Frmmain.vb
dt = WebDatabase.GetAllOrdersFromDatabase()**'this method is below**
For Each drow In dt.Rows
If CDbl(WinDSSStoreNumber) = 123 Or CDbl(WinDSSStoreNumber) = 124 Then
' Store 123 and 124 = customer service - only orders with qualifying source codes
my question is:
the above for each checks if the store is 123 or 124 but now I want to implement another for each loop that reads all the InvoiceHeader_Id that the second field in the datatable and then check if it has a bundle kit or not if it does then process it and update the isprocessed field second last in the datatable else process the orders without any bundle kit and update isprocessed for those as well. please any help is generously appreciated, please ask me any questions in the below comment before marking my question down.
WebData.vb
Public Function GetAllOrdersFromDatabase() As DataTable
DrivePath = "C:\Users\somjething\Documents\files\somefiles\"
Dim ds As DataTable = Nothing
WinDSS.connectionString = ConfigurationManager.AppSettings("WinDSS_Connection").Replace("%DrivePath%", DrivePath)
ds = WinDSS.GetSysMst()
If ds.Rows.Count > 0 Then
WinDSSStoreNumber = ds.Rows(0)("store_no")
End If
Dim dt As New DataTable()
Dim conn As New SqlConnection(ConfigurationManager.AppSettings("WebData_Connection") & ConfigurationManager.AppSettings("WebDataSource"))
Dim cmd As SqlCommand
Dim da As New SqlDataAdapter
conn.Open()
cmd = conn.CreateCommand()
cmd.CommandType = CommandType.Text
cmd.CommandText= SELECT InvoiceDetail_Id, InvoiceHeader_Id, ActualFreightCharge, AmountCollected,
ChargedActualFreight, CollectedExternally, CollectedThroughAR, DateInvoiced, InvoiceNo,
InvoiceType, LineSubTotal, MasterInvoiceNo, OrderInvoiceKey, Reference1, TotalAmount,
TotalTax, isprocessed, storetoprocess
FROM dbo.InvoiceHeader
WHERE (isprocessed = 0) AND (storetoprocess = N'123')
da.SelectCommand = cmd
da.Fill(dt)
conn.Close()
Return dt
End Function
Additoinal info
This is the information given to me by my manager:
loop throught each below
SELECT InvoiceDetail_Id, InvoiceHeader_Id, ActualFreightCharge, AmountCollected,
ChargedActualFreight, CollectedExternally, CollectedThroughAR, DateInvoiced, InvoiceNo,
InvoiceType, LineSubTotal, MasterInvoiceNo, OrderInvoiceKey, Reference1, TotalAmount,
TotalTax, isprocessed, storetoprocess
FROM dbo.InvoiceHeader WHERE (isprocessed = 0) AND (storetoprocess = N'195')
Use the above InvoiceHeader_Id to loop throught all of the order information. Process each Bundle (Kit/)
SELECT InvoiceHeader_Id, LineDetails_Id, LineDetail_Id, OrderLine_Id, GiftFlag, [References],
GiftWrap, IsBundleParent, KitCode, KitQty, LevelOfService, LineSeqNo, LineType,
MaxLineStatus, MaxLineStatusDesc, MinLineStatus, MinLineStatusDesc, MinShipByDate,
OpenQty, OrderHeaderKey, OrderLineKey, OrderedQty, OriginalOrderedQty, OtherCharges,
OverallStatus, PipelineKey, PrimeLineNo, ReceivingNode, RemainingQty, ReqCancelDate,
ReqDeliveryDate,
ReqShipDate, SCAC, ScacAndService, ScacAndServiceKey, ShipNode, ShipToID, ShipToKey,
StatusQuantity, SubLineNo, SubstituteItemID, isprocessed
FROM dbo.OrderLine
WHERE (isprocessed = 0) AND (InvoiceHeader_Id = 13) AND (IsBundleParent = 'Y')
ORDER BY PrimeLineNo, SubLineNo
For each record in the above list query below and add as Zero (0) dollar amount. The cost is associated with the information above record (you may have to query tables to ge the values)
Get the OrderLineKey from the above record and query this below to get the associated sub items.
SELECT TOP (100) PERCENT dbo.BundleParentLine.InvoiceHeader_Id AS BPL_InvoiceHeader_Id,
dbo.BundleParentLine.LineDetails_Id AS BPL_LineDetails_Id, dbo.BundleParentLine.LineDetail_Id AS BPL_LineDetail_Id, dbo.BundleParentLine.OrderLine_Id AS BPL_OrderLine_Id, dbo.BundleParentLine.BundleParentLine_id, dbo.BundleParentLine.SubLineNo AS BPL_SubLineNo, dbo.BundleParentLine.PrimeLineNo AS BPL_PrimeLineNo, dbo.BundleParentLine.OrderLineKey AS BPL_OrderLineKey, dbo.OrderLine.*
FROM dbo.BundleParentLine INNER JOIN dbo.OrderLine ON dbo.BundleParentLine.OrderLine_Id = dbo.OrderLine.OrderLine_Id AND dbo.BundleParentLine.LineDetail_Id = dbo.OrderLine.LineDetail_Id AND dbo.BundleParentLine.LineDetails_Id = dbo.OrderLine.LineDetails_Id AND dbo.BundleParentLine.InvoiceHeader_Id = dbo.OrderLine.InvoiceHeader_Id
WHERE (dbo.BundleParentLine.OrderLineKey = N'76873264832') AND (dbo.BundleParentLine.InvoiceHeader_Id = 13) AND (dbo.BundleParentLine.LineDetails_Id = 6) AND (dbo.OrderLine.isprocessed = 0)
ORDER BY BPL_PrimeLineNo, BPL_SubLineNo
After Processed, set isprocessed = 1
Use the above InvoiceHeader_Id to loop throught all of the order information
SELECT InvoiceHeader_Id, LineDetails_Id, LineDetail_Id, OrderLine_Id, GiftFlag, [References],
GiftWrap, IsBundleParent, KitCode, KitQty, LevelOfService, LineSeqNo,
LineType,
MaxLineStatus, MaxLineStatusDesc, MinLineStatus, MinLineStatusDesc, MinShipByDate,
OpenQty, OrderHeaderKey, OrderLineKey, OrderedQty,
OriginalOrderedQty,
OtherCharges, OverallStatus, PipelineKey, PrimeLineNo, ReceivingNode, RemainingQty,
ReqCancelDate, ReqDeliveryDate, ReqShipDate, SCAC,
ScacAndService,
ScacAndServiceKey, ShipNode, ShipToID, ShipToKey, StatusQuantity,
SubLineNo, SubstituteItemID, isprocessed
FROM dbo.OrderLine
WHERE (isprocessed = 0) AND (InvoiceHeader_Id = 13) AND (IsBundleParent <> 'Y')
ORDER BY PrimeLineNo, SubLineNo
After Processed, set isprocessed = 1
This is not an answer but I want to pose this to prompt you for some clarification and it's not practical in the comments.
First, close visual studio and open SQL Server Management Studio and connect to the database
We'll build some select statements to get the data back and then we can think about an UPDATE statement
This first query you posted gives you the unprocessed headers for store 195 (straight from your post). I don't know if you want to do this for all stores or not. Paste it into SSMS and run it
SELECT H.*
FROM dbo.InvoiceHeader H
WHERE H.isprocessed = 0 AND H.storetoprocess = N'195'
Now, this second query gives you the unprocessed lines against that header that have IsBundleParent='Y'.
Look! No loops!
SELECT H.*, L.*
FROM dbo.InvoiceHeader H
INNER JOIN
dbo.OrderLine L
ON L.InvoiceHeader_Id = H.InvoiceHeader_Id
WHERE H.isprocessed = 0 AND H.storetoprocess = N'195'
AND L.isprocessed = 0 AND L.IsBundleParent = 'Y'
Then in your explanation you have For each record in the above list query below and add as Zero (0) dollar amount which makes no sense to me so perhaps you could clarify
Now we'll add the third query in which adds BundleParentLine (which does have inner joins in it already, but it's a pretty strange list of join fields)
SELECT H.*, L.*, BPL.*
FROM dbo.InvoiceHeader H
INNER JOIN
dbo.OrderLine L
ON L.InvoiceHeader_Id = H.InvoiceHeader_Id
INNER JOIN
dbo.BundleParentLine BPL
ON BPL.OrderLine_Id = L.OrderLine_Id
AND BPL.LineDetail_Id = L.LineDetail_Id
AND BPL.LineDetails_Id = L.LineDetails_Id
AND BPL.InvoiceHeader_Id = L.InvoiceHeader_Id
WHERE H.isprocessed = 0 AND H.storetoprocess = N'195'
AND L.isprocessed = 0 AND L.IsBundleParent = 'Y'
Then in your explanation you have After Processed, set isprocessed = 1, but what is 'processed' here? Is it just setting it to processed in the table?
To do that you just write an UPDATE statement. Here's one way to do that to update just the header (don't run it though until we understand what you're trying to do). Is the problem here that you want to set header and line to processed at the same time?
UPDATE InvoiceHeader
SET Processed = 1
WHERE isprocessed = 0 AND storetoprocess = N'195'
The fourth query you have seems to account for the IsBundleParent <> 'Y' case
Again, we need to know what add as Zero (0) dollar amount and processed means to go any further.

Show count in SSRS using SQL Server

Below is my sql query
USE AdventureWorks2012
Select EDH.*,
case when EDH.DepartmentID between 1 and 5 then 'DEPT-A'
when EDH.DepartmentID between 5 and 9 then 'DEPT-B'
when EDH.DepartmentID between 9 and 30 then 'DEPT-C' end as [DEPT TYPE]---, count(EDH.DepartmentID)
from HumanResources.EmployeeDepartmentHistory EDH
left outer join HumanResources.Employee EM on EM.BusinessEntityID = EDH.BusinessEntityID
group by EDH.DepartmentID, EDH.BusinessEntityID, EDH.ShiftID, EDH.StartDate, EDH.EndDate, EDH.ModifiedDate
I'm bringing the Dept Type column either as Dept-A, B or C based on Case when Condition on Department ID.
Now in the SSRS report I want to show the count of the Department Column in the footer such as
Dept Count[A/B/C]: 49/195/46
How to show the count in the report? Should I modify the query or there is some change required in the report
You can use an expression like:
="Dept Count [A/B/C]: "
& Sum(IIf(Fields!DeptType.Value = "DEPT-A", 1, 0)) & "/"
& Sum(IIf(Fields!DeptType.Value = "DEPT-B", 1, 0)) & "/"
& Sum(IIf(Fields!DeptType.Value = "DEPT-C", 1, 0))
This will work as you have a set amount of department types. Use a conditional Sum with IIf to get the numbers in each account.
Works on some simplified data:

Need to use information from one qry to dictate an action on another

Ok so this is going to sound a little complicated. I want to somehow put some kind of function that will divide a table value by two when its Policy number matches up with a policy number in another table.
Here is the query where I want that functions
SELECT
qryReinsuranceDPA1_izzy.POLICY_NO,
qryReinsuranceDPA1_izzy.PHASE_CODE,
qryReinsuranceDPA1_izzy.SUB_PHASE_CODE,
qryReinsuranceDPA1_izzy.SchedNP,
qryReinsuranceDPA1_izzy.ProdType,
Sum(qryReinsuranceDPA1_izzy.SumOfAMOUNT_INFORCE) AS SumOfSumOfAMOUNT_INFORCE,
Sum(qryReinsuranceDPA1_izzy.SumOfPUA_FACE) AS SumOfSumOfPUA_FACE,
Sum(qryReinsuranceDPA1_izzy.SumOfOYT_FACE) AS SumOfSumOfOYT_FACE, TotalDPA = sum(case when qryReinsuranceDPA1_izzy.[SumOfNetDefExtraAdj] Is Null then qryReinsuranceDPA1_izzy.[SumOfNetDefPremiumAdj] else qryReinsuranceDPA1_izzy.[SumOfNetDefPremiumAdj] +qryReinsuranceDPA1_izzy.[SumOfNetDefExtraAdj] end),
qryReinsuranceDPA1_izzy.SumOfGROSS_ANNLZD_PREM,
qryReinsuranceDPA1_izzy.SumOfStatNetPremium,
qryReinsuranceDPA1_izzy.[SumOfStatNetPremium]/qryReinsuranceDPA1_izzy.[SumOfGROSS_ANNLZD_PREM] AS NetToGrossRatio,
qryReinsuranceDPA1_izzy.NetvsGrossInd,
DPA_NetPrem = case when qryReinsuranceDPA1_izzy.[NetvsGrossInd]='Net' then sum(qryReinsuranceDPA1_izzy.[SumOfStatNetPremium]) else sum([qryReinsuranceDPA1_izzy].[SumOfGROSS_ANNLZD_PREM]) end,
qryPolicyListforNYDefPRemAsset_Re.ReinType AS ReinType,
Sum(qryPolicyListforNYDefPRemAsset_Re.ReinsAmount) AS SumOfReinsAmount,
qryPolicyListforNYDefPRemAsset_Re.[ReinsAmount]/(qryReinsuranceDPA1_izzy.[SumOfAMOUNT_INFORCE]+qryReinsuranceDPA1_izzy.[SumOfOYT_FACE]+qryReinsuranceDPA1_izzy.[SumOfPUA_FACE]) AS [Reins%],
qryPolicyListforNYDefPRemAsset_Re.ReinsStatRsv AS ReinsStatRsv,
Sum(qryPolicyListforNYDefPRemAsset_Re.SumOfGROSS_ANNLZD_PREM) AS ReinsPrem, qryReinsuranceDPA1_izzy.PAID_TO_DATE,
qryReinsuranceDPA1_izzy.VAL_DATE,
qryReinsuranceDPA1_izzy.ISSUE_DATE
FROM qryPolicyListforNYDefPRemAsset_Re RIGHT JOIN
qryReinsuranceDPA1_izzy
ON
qryReinsuranceDPA1_izzy.POLICY_NO = qryPolicyListforNYDefPRemAsset_Re.POLICY_NO
AND qryReinsuranceDPA1_izzy.PHASE_CODE = qryPolicyListforNYDefPRemAsset_Re.PHASE_CODE AND
qryReinsuranceDPA1_izzy.SUB_PHASE_CODE= qryPolicyListforNYDefPRemAsset_Re.SUB_PHASE_CODE
GROUP BY
qryReinsuranceDPA1_izzy.POLICY_NO,
qryReinsuranceDPA1_izzy.PHASE_CODE,
qryReinsuranceDPA1_izzy.SUB_PHASE_CODE,
qryReinsuranceDPA1_izzy.SchedNP,
qryReinsuranceDPA1_izzy.ProdType,
qryReinsuranceDPA1_izzy.SumOfGROSS_ANNLZD_PREM,
qryReinsuranceDPA1_izzy.SumOfStatNetPremium,
qryReinsuranceDPA1_izzy.[SumOfStatNetPremium]/qryReinsuranceDPA1_izzy.[SumOfGROSS_ANNLZD_PREM],
qryReinsuranceDPA1_izzy.NetvsGrossInd,
qryPolicyListforNYDefPRemAsset_Re.ReinType,
qryPolicyListforNYDefPRemAsset_Re.[ReinsAmount]/(qryReinsuranceDPA1_izzy.[SumOfAMOUNT_INFORCE]+qryReinsuranceDPA1_izzy.[SumOfOYT_FACE]+qryReinsuranceDPA1_izzy.[SumOfPUA_FACE]),
qryPolicyListforNYDefPRemAsset_Re.ReinsStatRsv,
qryReinsuranceDPA1_izzy.PAID_TO_DATE,
qryReinsuranceDPA1_izzy.VAL_DATE,
qryReinsuranceDPA1_izzy.ISSUE_DATE
GO
and this is the qry that contains the policy numbers that I want divided by 2 in the above qry.
SELECT
qryReinsuranceDPA1.POLICY_NO,
qryReinsuranceDPA1.PHASE_CODE,
qryReinsuranceDPA1.SUB_PHASE_CODE,
qryReinsuranceDPA1.ProdType,
TotalDPA = Sum(case when [SumOfNetDefExtraAdj] Is Null then [SumOfNetDefPremiumAdj] else [SumOfNetDefPremiumAdj] + SumOfNetDefExtraAdj end),
Sum(1) AS Expr1
FROM qryPolicyListforNYDefPRemAsset_Re RIGHT JOIN qryReinsuranceDPA1
ON
qryReinsuranceDPA1.POLICY_NO = qryPolicyListforNYDefPRemAsset_Re.POLICY_NO AND
qryReinsuranceDPA1.PHASE_CODE= qryPolicyListforNYDefPRemAsset_Re.PHASE_CODE AND
qryReinsuranceDPA1.SUB_PHASE_CODE = qryPolicyListforNYDefPRemAsset_Re.SUB_PHASE_CODE
GROUP BY qryReinsuranceDPA1.POLICY_NO,
qryReinsuranceDPA1.PHASE_CODE,
qryReinsuranceDPA1.SUB_PHASE_CODE,
qryReinsuranceDPA1.ProdType
HAVING (((Sum(1))<>1))
GO
quick example. Say that the Policy number 064543200 is located in the results of that second qry. I then want the number located in first qry in Total DPA assosciated with that Policy number to be divided by 2.
If this is still confusing please let me know and I will try to explain better. Both are views.

Dynamic column value with group by (sql server and Linq)

i have a table Plan with following sample data
i want to aggregate the result by PlanMonth and for PlanStatus i want that if any of its (in a group) values is Drafted i get drafted in the result and Under Approval otherwise. i have done it using following query
select PlanMonth, case when Flag=1 then 'Drafted' else 'Under Approval' end as PlanStatus
from
(select p.PlanMonth, Max(CASE WHEN p.PlanStatus = 'Drafted' THEN 1 ELSE 0 END) Flag
from Plans p
group by p.PlanMonth
) inquery
i have consulted this blog post. Is there something wrong with it? Moreover, if someone can help me translate it to linq i will be grateful
The query you have will work.
With the sample data you have provided it can be simplified a bit.
select p.PlanMonth,
min(p.PlanStatus) as PlanStatus
from Plans as p
group by p.PlanMonth
This will not work if you have values in PlanStatus that is alphabetically sorted before Drafted.
Following Linq query worked for me
return (from p in db.mktDrVisitPlans
group p by p.PlanMonth into grop
select
new VMVisitPlan
{
PlanMonth = grop.Key
PlanStatus = grop.Any(x=>x.p.PlanStatus == "Drafted")?"Hold":"Under Approval",
}).ToList();

Resources