Sum(IIF( including results with 0 count - sql

Hey All i am using sum iff to return a count based on multiple criteria.
i am basically running a report on calls recieved per site, however i need sites with 0 calls included in the result set, with the value of 0 or even Null, if they have no calls for that week.
only issue is that my where cluase has only included sites that have had calls in the week
Any ideas.
Code:
SELECT
d.sitename,
count(c.Chargeablecalls) AS All_Calls,
SUM(IIf(c.ChargeableCalls Like "Chargeable",1,0)) AS Chargeable_calls,
d.sitetype
FROM
(Callstatus AS s LEFT JOIN statusconversion AS c ON s.description=c.reportheading)
INNER JOIN sitedetails AS d ON s.zone=d.zone
WHERE s.date_loaded BETWEEN
(SELECT reportdate FROM reportMonth) AND (SELECT priorweek FROM reportMonth)
GROUP BY d.sitename, d.sitetype;

You need a RIGHT JOIN for sitedetails in order to get all the sites even those with no calls.
You may need to do the first half of query separately and then use that query in the main query.

create a new query - qryCallStatus:
SELECT DISTINCT zone, description
FROM Callstatus, reportMonth
WHERE
Callstatus.date_loaded BETWEEN reportMonth.reportdate AND reportMonth.priorweek;
Then change your output query to:
SELECT
d.sitename,
count(c.Chargeablecalls) AS All_Calls,
SUM(IIf(c.ChargeableCalls Like "Chargeable",1,0)) AS Chargeable_calls,
d.sitetype
FROM
(sitedetails AS d LEFT JOIN qryCallStatus AS s ON d.zone=s.zone)
LEFT JOIN statusconversion AS c ON s.description=c.reportheading
GROUP BY d.sitename, d.sitetype;

Related

Calculate number of distinct instances of value in column

long time lurker. I've searched and searched though none of the solutions work for me.
I'm working in a Sybase (ASE) db (most mssql/mysql transactional db solutions will work just fine)
In my example, I'm trying to calculate/count the number of times a specific 'party_id' is listed in a column. The problem I'm having is that it's only counting FOR each row- so of course the count is always going to be 1.
See output:
(I would like for party_id 130568 to show '2' in the refs column, 125555 to show '5', etc.)
output
Here is my query:
select
count(distinct p.party_id) as refs,
p.party_id,
sp_first_party(casenum),
c.casenum,
mld.mailing_list,
p.our_client
from cases c
inner join party p on c.casenum=p.case_id
inner join names n on n.names_id=p.party_id
inner join mailing_list_defined mld on n.names_id=mld.names_id
where
mld.mailing_list like 'Mattar Stars'
and mld.addr_type like 'Home'
and n.deceased='N'
and p.our_client='Y'
group by p.party_id, c.casenum, mld.mailing_list, p.our_client
order by sp_first_party(casenum) asc
Any tips would be greatly appreciated.
Thank you
Sounds like you need to be using an APPLY statement. Not sure if the join criteria on the APPLY statement is correct, but you should be able to extrapolate the logic. See if that will work with Sybase.
SELECT pic.PartyInstanceCount AS refs
,p.party_id
,sp_first_party(casenum)
,c.casenum
,mld.mailing_list
,p.our_client
FROM cases AS c
INNER JOIN party AS p ON c.casenum = p.case_id
INNER JOIN names AS n ON n.names_id = p.party_id
INNER JOIN mailing_list_defined AS mld ON n.names_id = mld.names_id
OUTER APPLY (
SELECT COUNT(1) AS PartyInstanceCount
FROM party p2
WHERE p2.case_id = c.casenum
) pic
WHERE mld.mailing_list LIKE 'Mattar Stars'
AND mld.addr_type LIKE 'Home'
AND n.deceased = 'N'
AND p.our_client = 'Y'
ORDER BY
sp_first_party(casenum) ASC

COUNT is outputting more than one row

I am having a problem with my SQL query using the count function.
When I don't have an inner join, it counts 55 rows. When I add the inner join into my query, it adds a lot to it. It suddenly became 102 rows.
Here is my SQL Query:
SELECT COUNT([fmsStage].[dbo].[File].[FILENUMBER])
FROM [fmsStage].[dbo].[File]
INNER JOIN [fmsStage].[dbo].[Container]
ON [fmsStage].[dbo].[File].[FILENUMBER] = [fmsStage].[dbo].[Container].[FILENUMBER]
WHERE [fmsStage].[dbo].[File].[RELATIONCODE] = 'SHIP02'
AND [fmsStage].[dbo].[Container].DELIVERYDATE BETWEEN '2016-10-06' AND '2016-10-08'
GROUP BY [fmsStage].[dbo].[File].[FILENUMBER]
Also, I have to do TOP 1 at the SELECT statement because it returns 51 rows with random numbers inside of them. (They are probably not random, but I can't figure out what they are.)
What do I have to do to make it just count the rows from [fmsStage].[dbo].[file].[FILENUMBER]?
First, your query would be much clearer like this:
SELECT COUNT(f.[FILENUMBER])
FROM [fmsStage].[dbo].[File] f INNER JOIN
[fmsStage].[dbo].[Container] c
ON v.[FILENUMBER] = c.[FILENUMBER]
WHERE f.[RELATIONCODE] = 'SHIP02' AND
c.DELIVERYDATE BETWEEN '2016-10-06' AND '2016-10-08';
No GROUP BY is necessary. Otherwise you'll just one row per file number, which doesn't seem as useful as the overall count.
Note: You might want COUNT(DISTINCT f.[FILENUMBER]). Your question doesn't provide enough information to make a judgement.
Just remove GROUP BY Clause
SELECT COUNT([fmsStage].[dbo].[File].[FILENUMBER])
FROM [fmsStage].[dbo].[File]
INNER JOIN [fmsStage].[dbo].[Container]
ON [fmsStage].[dbo].[File].[FILENUMBER] = [fmsStage].[dbo].[Container].[FILENUMBER]
WHERE [fmsStage].[dbo].[File].[RELATIONCODE] = 'SHIP02'
AND [fmsStage].[dbo].[Container].DELIVERYDATE BETWEEN '2016-10-06' AND '2016-10-08'

CRYSTAL REPORTS - Display all records where value appears multiple times in the table

For example, I have a report with twenty columns and I want to return ONLY the rows where the value in Column 9 appears more than once. I'm fairly new to this and so far I have not figured out an answer.
Other selection criteria includes date range, and service details. The end result would be a report of members who received service more than once during the identified period.
I have seen a couple of examples returning only one column but I do not know how to apply that logic to my scenario.
SELECT "MASTERS"."MEMBNAME", "MASTERS"."MEMBID", "MASTERS"."OPT", "MASTERS"."HPCODE", "MASTERS"."CLAIMNO", "MASTERS"."CROSSREF_ID", "DETAILS"."FROMDATESVC", "DETAILS"."TODATESVC", "MASTERS"."ADMDATE", "MASTERS"."DSCHDATE", "MASTERS"."DATERECD", "DETAILS"."DIAGCODE", "DIAG_CODES"."DIAGDESC", "MASTERS"."PLACESVC", "DETAILS"."PROCCODE", "DETAILS"."HSERVICECD", "DETAILS"."PROCDESC", "DETAILS"."HSERVICEDESC", "P_MASTERS"."FULLNAME", "V_MASTERS"."VENDORNM", "MASTERS"."SPEC", "P_MASTERS"."CLASS", "DETAILS"."BILLED", "DETAILS"."CONTRVAL", "DETAILS"."ADJUST", "DETAILS"."NET", "DETAILS"."INTEREST", "DETAILS"."QTY", "DETAILS"."ADJCODE", "MASTERS"."COMPANY_ID", "MEMB_COMPANY_V"."BIRTH", "ADJUST_CODES_V"."DESCR", "MEMB_COMPANY_V"."SEX", "P_MASTERS_1"."REV_FULLNAME", "MEMB_COMPANY_V"."OPFROMDT", "MEMB_COMPANY_V"."OPTHRUDT", "V_MASTERS"."VENDORID", "P_MASTERS"."CONTRACT", "ME_V"."MEMOLINE1", "DETAILS"."COPAY", "DETAILS"."SEQUENCE", "DETAILS"."DATEPAID", "DETAILS"."CHECKNO", "P_MASTERS_1"."ACCOUNT", "MASTERS"."ADMTYPE", "MASTERS"."ADMSOURCE", "MASTERS"."CONTRVAL", "MASTERS"."STATUS", "MASTERS"."DATEPAID", "MASTERS"."CHPREFIX", "MASTERS"."NET"
FROM ((((((("Datawarehouse"."dbo"."MASTERS" "MASTERS" INNER JOIN "Datawarehouse"."dbo"."DETAILS" "DETAILS" ON "MASTERS"."CLAIMNO"="DETAILS"."CLAIMNO") INNER JOIN "Datawarehouse"."dbo"."V_MASTERS" "V_MASTERS" ON "MASTERS"."VENDOR"="V_MASTERS"."VENDORID") INNER JOIN "Datawarehouse"."dbo"."P_MASTERS" "P_MASTERS" ON ("MASTERS"."COMPANY_ID"="P_MASTERS"."COMPANY_ID") AND ("MASTERS"."PROVID"="P_MASTERS"."PROVID")) INNER JOIN "Datawarehouse"."dbo"."MEMB_COMPANY_V" "MEMB_COMPANY_V" ON ("MASTERS"."COMPANY_ID"="MEMB_COMPANY_V"."COMPANY_ID") AND ("MASTERS"."MEMBID"="MEMB_COMPANY_V"."MEMBID")) LEFT OUTER JOIN "Datawarehouse"."dbo"."ME_V" "ME_V" ON ("MASTERS"."CLAIMNO"="ME_V"."CLAIMNO") AND ("MASTERS"."COMPANY_ID"="ME_V"."COMPANY_ID")) INNER JOIN "Datawarehouse"."dbo"."DIAG_CODES" "DIAG_CODES" ON "DETAILS"."DIAGCODE"="DIAG_CODES"."DIAGCODE") LEFT OUTER JOIN "Datawarehouse"."dbo"."ADJUST_CODES_V" "ADJUST_CODES_V" ON "DETAILS"."ADJCODE"="ADJUST_CODES_V"."CODE") LEFT OUTER JOIN "Datawarehouse"."dbo"."P_MASTERS" "P_MASTERS_1" ON ("MEMB_COMPANY_V"."COMPANY_ID"="P_MASTERS_1"."COMPANY_ID") AND ("MEMB_COMPANY_V"."PCP"="P_MASTERS_1"."PROVID")
WHERE ("MASTERS"."STATUS"='9' AND "MASTERS"."COMPANY_ID"='LWDLOM' AND ("DETAILS"."ADJCODE" IS NULL OR NOT ("DETAILS"."ADJCODE" LIKE 'D%' OR "DETAILS"."ADJCODE" LIKE 'KILL%')) AND "DETAILS"."NET"=0 AND "P_MASTERS"."CLASS"='51' AND ("MASTERS"."HPCODE"='GSMH' OR "MASTERS"."HPCODE"='HENS' OR "MASTERS"."HPCODE"='SCAS') AND "MASTERS"."CONTRVAL"<>0 OR "MASTERS"."CHPREFIX"=2 AND "MASTERS"."STATUS"='9' AND "MASTERS"."COMPANY_ID"='LWDLOM' AND ("DETAILS"."ADJCODE" IS NULL OR NOT ("DETAILS"."ADJCODE" LIKE 'D%' OR "DETAILS"."ADJCODE" LIKE 'KILL%')) AND "P_MASTERS"."CLASS"<>'51' AND ("MASTERS"."HPCODE"='GSMH' OR "MASTERS"."HPCODE"='HENS' OR "MASTERS"."HPCODE"='SCAS') AND "MASTERS"."NET"<>0) AND ("DETAILS"."FROMDATESVC">={ts '2014-01-01 00:00:00'} AND "DETAILS"."FROMDATESVC"<{ts '2015-12-31 00:00:01'}) AND "MASTERS"."DATEPAID"<{ts '2015-05-31 00:00:01'}
ORDER BY "MASTERS"."CLAIMNO", "DETAILS"."SEQUENCE"
This is a simplified query compared to yours. You should only need to add the COUNT() function to column 9 and the GROUP BY after the WHERE statement and before the ORDER BY statement.
SELECT COUNT(YourColumn9Name) AS YourColumn9Name
FROM Masters
GROUP BY YourColumn9Name HAVING (COUNT(YourColumn9Name)>1)

Include missing years in Group By query

I am fairly new in Access and SQL programming. I am trying to do the following:
Sum(SO_SalesOrderPaymentHistoryLineT.Amount) AS [Sum Of PaymentPerYear]
and group by year even when there is no amount in some of the years. I would like to have these years listed as well for a report with charts. I'm not certain if this is possible, but every bit of help is appreciated.
My code so far is as follows:
SELECT
Base_CustomerT.SalesRep,
SO_SalesOrderT.CustomerId,
Base_CustomerT.Customer,
SO_SalesOrderPaymentHistoryLineT.DatePaid,
Sum(SO_SalesOrderPaymentHistoryLineT.Amount) AS [Sum Of PaymentPerYear]
FROM
Base_CustomerT
INNER JOIN (
SO_SalesOrderPaymentHistoryLineT
INNER JOIN SO_SalesOrderT
ON SO_SalesOrderPaymentHistoryLineT.SalesOrderId = SO_SalesOrderT.SalesOrderId
) ON Base_CustomerT.CustomerId = SO_SalesOrderT.CustomerId
GROUP BY
Base_CustomerT.SalesRep,
SO_SalesOrderT.CustomerId,
Base_CustomerT.Customer,
SO_SalesOrderPaymentHistoryLineT.DatePaid,
SO_SalesOrderPaymentHistoryLineT.PaymentType,
Base_CustomerT.IsActive
HAVING
(((SO_SalesOrderPaymentHistoryLineT.PaymentType)=1)
AND ((Base_CustomerT.IsActive)=Yes))
ORDER BY
Base_CustomerT.SalesRep,
Base_CustomerT.Customer;
You need another table with all years listed -- you can create this on the fly or have one in the db... join from that. So if you had a table called alltheyears with a column called y that just listed the years then you could use code like this:
WITH minmax as
(
select min(year(SO_SalesOrderPaymentHistoryLineT.DatePaid) as minyear,
max(year(SO_SalesOrderPaymentHistoryLineT.DatePaid) as maxyear)
from SalesOrderPaymentHistoryLineT
), yearsused as
(
select y
from alltheyears, minmax
where alltheyears.y >= minyear and alltheyears.y <= maxyear
)
select *
from yearsused
join ( -- your query above goes here! -- ) T
ON year(T.SO_SalesOrderPaymentHistoryLineT.DatePaid) = yearsused.y
You need a data source that will provide the year numbers. You cannot manufacture them out of thin air. Supposing you had a table Interesting_year with a single column year, populated, say, with every distinct integer between 2000 and 2050, you could do something like this:
SELECT
base.SalesRep,
base.CustomerId,
base.Customer,
base.year,
Sum(NZ(data.Amount)) AS [Sum Of PaymentPerYear]
FROM
(SELECT * FROM Base_CustomerT INNER JOIN Year) AS base
LEFT JOIN
(SELECT * FROM
SO_SalesOrderT
INNER JOIN SO_SalesOrderPaymentHistoryLineT
ON (SO_SalesOrderPaymentHistoryLineT.SalesOrderId = SO_SalesOrderT.SalesOrderId)
) AS data
ON ((base.CustomerId = data.CustomerId)
AND (base.year = Year(data.DatePaid))),
WHERE
(data.PaymentType = 1)
AND (base.IsActive = Yes)
AND (base.year BETWEEN
(SELECT Min(year(DatePaid) FROM SO_SalesOrderPaymentHistoryLineT)
AND (SELECT Max(year(DatePaid) FROM SO_SalesOrderPaymentHistoryLineT))
GROUP BY
base.SalesRep,
base.CustomerId,
base.Customer,
base.year,
ORDER BY
base.SalesRep,
base.Customer;
Note the following:
The revised query first forms the Cartesian product of BaseCustomerT with Interesting_year in order to have base customer data associated with each year (this is sometimes called a CROSS JOIN, but it's the same thing as an INNER JOIN with no join predicate, which is what Access requires)
In order to have result rows for years with no payments, you must perform an outer join (in this case a LEFT JOIN). Where a (base customer, year) combination has no associated orders, the rest of the columns of the join result will be NULL.
I'm selecting the CustomerId from Base_CustomerT because you would sometimes get a NULL if you selected from SO_SalesOrderT as in the starting query
I'm using the Access Nz() function to convert NULL payment amounts to 0 (from rows corresponding to years with no payments)
I converted your HAVING clause to a WHERE clause. That's semantically equivalent in this particular case, and it will be more efficient because the WHERE filter is applied before groups are formed, and because it allows some columns to be omitted from the GROUP BY clause.
Following Hogan's example, I filter out data for years outside the overall range covered by your data. Alternatively, you could achieve the same effect without that filter condition and its subqueries by ensuring that table Intersting_year contains only the year numbers for which you want results.
Update: modified the query to a different, but logically equivalent "something like this" that I hope Access will like better. Aside from adding a bunch of parentheses, the main difference is making both the left and the right operand of the LEFT JOIN into a subquery. That's consistent with the consensus recommendation for resolving Access "ambiguous outer join" errors.
Thank you John for your help. I found a solution which works for me. It looks quiet different but I learned a lot out of it. If you are interested here is how it looks now.
SELECT DISTINCTROW
Base_Customer_RevenueYearQ.SalesRep,
Base_Customer_RevenueYearQ.CustomerId,
Base_Customer_RevenueYearQ.Customer,
Base_Customer_RevenueYearQ.RevenueYear,
CustomerPaymentPerYearQ.[Sum Of PaymentPerYear]
FROM
Base_Customer_RevenueYearQ
LEFT JOIN CustomerPaymentPerYearQ
ON (Base_Customer_RevenueYearQ.RevenueYear = CustomerPaymentPerYearQ.[RevenueYear])
AND (Base_Customer_RevenueYearQ.CustomerId = CustomerPaymentPerYearQ.CustomerId)
GROUP BY
Base_Customer_RevenueYearQ.SalesRep,
Base_Customer_RevenueYearQ.CustomerId,
Base_Customer_RevenueYearQ.Customer,
Base_Customer_RevenueYearQ.RevenueYear,
CustomerPaymentPerYearQ.[Sum Of PaymentPerYear]
;

Timeout running SQL query

I'm trying to using the aggregation features of the django ORM to run a query on a MSSQL 2008R2 database, but I keep getting a timeout error. The query (generated by django) which fails is below. I've tried running it directs the SQL management studio and it works, but takes 3.5 min
It does look it's aggregating over a bunch of fields which it doesn't need to, but I wouldn't have though that should really cause it to take that long. The database isn't that big either, auth_user has 9 records, ticket_ticket has 1210, and ticket_watchers has 1876. Is there something I'm missing?
SELECT
[auth_user].[id],
[auth_user].[password],
[auth_user].[last_login],
[auth_user].[is_superuser],
[auth_user].[username],
[auth_user].[first_name],
[auth_user].[last_name],
[auth_user].[email],
[auth_user].[is_staff],
[auth_user].[is_active],
[auth_user].[date_joined],
COUNT([tickets_ticket].[id]) AS [tickets_captured__count],
COUNT(T3.[id]) AS [assigned_tickets__count],
COUNT([tickets_ticket_watchers].[ticket_id]) AS [tickets_watched__count]
FROM
[auth_user]
LEFT OUTER JOIN [tickets_ticket] ON ([auth_user].[id] = [tickets_ticket].[capturer_id])
LEFT OUTER JOIN [tickets_ticket] T3 ON ([auth_user].[id] = T3.[responsible_id])
LEFT OUTER JOIN [tickets_ticket_watchers] ON ([auth_user].[id] = [tickets_ticket_watchers].[user_id])
GROUP BY
[auth_user].[id],
[auth_user].[password],
[auth_user].[last_login],
[auth_user].[is_superuser],
[auth_user].[username],
[auth_user].[first_name],
[auth_user].[last_name],
[auth_user].[email],
[auth_user].[is_staff],
[auth_user].[is_active],
[auth_user].[date_joined]
HAVING
(COUNT([tickets_ticket].[id]) > 0 OR COUNT(T3.[id]) > 0 )
EDIT:
Here are the relevant indexes (excluding those not used in the query):
auth_user.id (PK)
auth_user.username (Unique)
tickets_ticket.id (PK)
tickets_ticket.capturer_id
tickets_ticket.responsible_id
tickets_ticket_watchers.id (PK)
tickets_ticket_watchers.user_id
tickets_ticket_watchers.ticket_id
EDIT 2:
After a bit of experimentation, I've found that the following query is the smallest that results in the slow execution:
SELECT
COUNT([tickets_ticket].[id]) AS [tickets_captured__count],
COUNT(T3.[id]) AS [assigned_tickets__count],
COUNT([tickets_ticket_watchers].[ticket_id]) AS [tickets_watched__count]
FROM
[auth_user]
LEFT OUTER JOIN [tickets_ticket] ON ([auth_user].[id] = [tickets_ticket].[capturer_id])
LEFT OUTER JOIN [tickets_ticket] T3 ON ([auth_user].[id] = T3.[responsible_id])
LEFT OUTER JOIN [tickets_ticket_watchers] ON ([auth_user].[id] = [tickets_ticket_watchers].[user_id])
GROUP BY
[auth_user].[id]
The weird thing is that if I comment out any two lines in the above, it runs in less that 1s, but it doesn't seem to matter which lines I remove (although obviously I can't remove a join without also removing the relevant SELECT line).
EDIT 3:
The python code which generated this is:
User.objects.annotate(
Count('tickets_captured'),
Count('assigned_tickets'),
Count('tickets_watched')
)
A look at the execution plan shows that SQL Server is first doing a cross-join on all the table, resulting in about 280 million rows, and 6Gb of data. I assume that this is where the problem lies, but why is it happening?
SQL Server is doing exactly what it was asked to do. Unfortunately, Django is not generating the right query for what you want. It looks like you need to count distinct, instead of just count: Django annotate() multiple times causes wrong answers
As for why the query works that way: The query says to join the four tables together. So say an author has 2 captured tickets, 3 assigned tickets, and 4 watched tickets, the join will return 2*3*4 tickets, one for each combination of tickets. The distinct part will remove all the duplicates.
what about this?
SELECT auth_user.*,
C1.tickets_captured__count
C2.assigned_tickets__count
C3.tickets_watched__count
FROM
auth_user
LEFT JOIN
( SELECT capturer_id, COUNT(*) AS tickets_captured__count
FROM tickets_ticket GROUP BY capturer_id ) AS C1 ON auth_user.id = C1.capturer_id
LEFT JOIN
( SELECT responsible_id, COUNT(*) AS assigned_tickets__count
FROM tickets_ticket GROUP BY responsible_id ) AS C2 ON auth_user.id = C2.responsible_id
LEFT JOIN
( SELECT user_id, COUNT(*) AS tickets_watched__count
FROM tickets_ticket_watchers GROUP BY user_id ) AS C3 ON auth_user.id = C3.user_id
WHERE C1.tickets_captured__count > 0 OR C2.assigned_tickets__count > 0
--WHERE C1.tickets_captured__count is not null OR C2.assigned_tickets__count is not null -- also works (I think with beter performance)