Add where clause to count and not entire query without using subquery - sql

The below query works but the "o.opendate is not null and o.orderdate is not null and o.closedate is null and o.canceldate is null" portion of the where clause needs to only apply to the orderID count (orderCount). Right now it is applying to the entire result set and that is not what I want. How can I change the query to do this? Also these tables are very large so I am relying heavily on indexes and trying not to use subquerys for performance reasons. Any help would be appreciated
select s.ZipCode, count(o.[OrderID]) orderCount, b.Longitude, b.Latitude, b.ordering
from ZipCodeServiceAvailability s
left join pdx_orders_view o on s.ZipCode = left(o.[ZipCode], 5)
left join ZipCodeBoundaries b on s.ZipCode = b.ZipCode
Where s.state = 'TX' and Ordering % 10 = 0 and
o.opendate is not null and o.orderdate is not null and o.closedate is null and o.canceldate is null
Group By s.ZipCode, IsServiced, b.Longitude, b.Latitude, b.Ordering
Order by s.ZipCode, b.Ordering

You need a case statement with a SUM:
select sum(case when o.opendate is not null and o.orderdate is not null and o.closedate is null and o.canceldate is null
then 1 else 0
end) as OrderCount
You should then remove the conditions from the where clause.

You can do what you want with a having clause.
select s.ZipCode, count(o.[OrderID]) orderCount, b.Longitude, b.Latitude, b.ordering
from ZipCodeServiceAvailability s
left join pdx_orders_view o on s.ZipCode = left(o.[ZipCode], 5)
left join ZipCodeBoundaries b on s.ZipCode = b.ZipCode
Where s.state = 'TX' and Ordering % 10 = 0 and
o.opendate is not null
Group By s.ZipCode, IsServiced, b.Longitude, b.Latitude, b.Ordering
Having count(o.[OrderID]) is not null
Order by s.ZipCode, b.Ordering

Related

Avoid NULL value in CASE SQL SERVER

How to avoid NULL values in CASE and SUM by P.Id. Problem is that i have more than one DPB.ProductTypeId in DPB table
SELECT P.[Id],
CASE
WHEN DPB.ProductTypeId = 1 THEN SUM(DPB.BonusAmount)
END AS [CasinoBonus]
FROM Player P
JOIN PlayerBonus DPB ON P.[Id] = DPB.[PlayerId]
group by P.[Id],DPB.ProductTypeId
use case when inside sum
SELECT P.[Id],
sum(CASE
WHEN DPB.ProductTypeId = 1 THEN DPB.BonusAmount
else 0
END) AS [CasinoBonus]
FROM Player P
JOIN PlayerBonus DPB ON P.[Id] = DPB.[PlayerId]
where P.[Id] is not null and DPB.[PlayerId] is not null
group by P.[Id],DPB.ProductTypeId
The case should be the argument to the sum(). You query should look like this:
SELECT P.[Id],
SUM(CASE WHEN DPB.ProductTypeId = 1 THEN DPB.BonusAmount
END) AS [CasinoBonus]
FROM Player P JOIN
PlayerBonus DPB
ON P.[Id] = DPB.[PlayerId]
GROUP BY P.[Id];
Note that you don't want DPB.ProductTypeId in the GROUP BY.
That said, you may simply want:
SELECT P.[Id],
SUM(DPB.BonusAmount) AS [CasinoBonus]
FROM Player P LEFT JOIN
PlayerBonus DPB
ON P.[Id] = DPB.[PlayerId] AND
DPB.ProductTypeId = 1
GROUP BY P.[Id];
Moving the condition to the WHERE clause removes the need for the CASE entirely. The LEFT JOIN keeps all players, even those that don't have that product type.

How to group database column?

I need to get a sales Ref. wise report which have several filters. I tried this query to generate the report.
SELECT
sp.SlpCode,
sp.SlpName,
sp.Telephone,
COUNT(od.DocNum) count,
ISNULL((SELECT COUNT(od.U_ArtWork) WHERE od.U_ArtWork = 'NotRec'), 0) Artwork,
ISNULL((SELECT COUNT(od.U_DetailPending) WHERE od.U_DetailPending = 'No'), 0) DetailPrinting
FROM
OSLP sp
LEFT JOIN
ORDR od ON SP.SlpCode = od.SlpCode
WHERE
sp.Telephone IS NOT NULL
GROUP BY
sp.SlpCode, sp.SlpName, sp.Telephone,
od.U_ArtWork, od.U_DetailPending
ORDER BY
sp.SlpName ASC;
The results are like this:
But I need those results like this:
You may try aggregating only on the three columns SlpCode, SlpName, and Telephone:
SELECT
sp.SlpCode,
sp.SlpName,
sp.Telephone,
COUNT(od.DocNum) count,
COUNT(CASE WHEN od.U_ArtWork = 'NotRec' THEN 1 END) AS Artwork,
COUNT(CASE WHEN od.U_DetailPending = 'No' THEN 1 END) AS DetailPrinting
FROM OSLP sp
LEFT JOIN ORDR od
ON SP.SlpCode = od.SlpCode
WHERE
sp.Telephone IS NOT NULL
GROUP BY
sp.SlpCode,
sp.SlpName,
sp.Telephone,
ORDER BY
sp.SlpName;
Remove od.U_ArtWork,od.U_DetailPending from group by - you are using these columns in aggregation so no need to add in group by clause
SELECT
sp.SlpCode,
sp.SlpName,
sp.Telephone,
COUNT(od.DocNum) count,
COUNT(case when od.U_ArtWork = 'NotRec' then od.U_ArtWork end) Artwork,
COUNT(case when od.U_DetailPending='No' then od.U_DetailPending end) DetailPrinting
FROM OSLP sp
LEFT JOIN ORDR od
ON SP.SlpCode = od.SlpCode
WHERE
sp.Telephone IS NOT NULL
GROUP BY
sp.SlpCode,
sp.SlpName,
sp.Telephone
ORDER BY
sp.SlpName ASC

Join 2 tables even with null values and sum each row

See pics below of what i want to do with my sql statement. I have used a left join and ISNULL to get all the results fine except for I don't get the total, which I want to sum the numbers for each customer. All table b values are integers.
Select a.CustomerId, a.FName, a.LName, b.mtg1, b.mtg2, b.mtg3, b.mtg4 From Customer a Left Join Hours b On a.CustomerID = b.CustomerID group by a.Lname
The GROUP BY will make it a bit difficult to captured all the necessary data. Also, the sum of different columns will require the use of COALESCE(column, 0) so as to use zero as the value if the column is null because if not done, your total will come back asNULL`.
One possible solution will is:
SELECT a.CustId, a.FName, a.LName, SUM(b.mtg1), SUM(b.mtg2), SUM(b.mtg3), SUM(b.mtg4), (COALESCE(SUM(b.mtg1), 0) + COALESCE(SUM(b.mtg2), 0) + COALESCE(SUM(b.mtg3), 0) + COALESCE(SUM(b.mtg4), 0)) AS total
FROM table_a a
LEFT JOIN table_b b ON(b.CustID = a.CustId)
GROUP BY a.CustID, a.FName, a.LName
with cte as
(
select flname+', '+fname as Name,
mtg1,mtg2,mtg3,mtg4,
isnull(((case when mtg1 is null then 0 else mtg1 end)+
(case when mtg2 is null then 0 else mtg2 end)+
(case when mtg3 is null then 0 else mtg3 end)+
(case when mtg4 is null then 0 else mtg4 end)),0) as total
from a left join b
on a.custid = b.custid
)
select name,
isnull(mtg1,0) as mtg1,
isnull(mtg2,0) as mtg2,
isnull(mtg3,0) as mtg3,
isnull(mtg4,0) as mtg4,
total
from cte
order by 1

SQL Sum is counting more than once

I am having difficulty with this. This query worked fine in calculating the sums until I put the first inner join in. In the table tbl_companies there are multiple entries per company, for example the table could look like this:
priority company externalip
1 bla 9.9.9.9
1 bla 3.3.3.3
1 company2 3.56.6.6
In the below query the sum (that calculates As TotalWithoutNew and TotalAllId is doubling when there is more than one entry for the company, and tripling if there is three etc. What I want it to do is simply bring back the priority from the table tbl_companies
SELECT b.company,
b.priority,
i.concom,
Coalesce (SUM(CASE
WHEN c.category_id = '30' THEN 0
ELSE t.logmins
END), 0) AS totalwithoutnew,
Coalesce (SUM(t.logmins), 0) AS totalallid
FROM helpdesk3.dbo.inquiry AS i
INNER JOIN [Check].[dbo].[tbl_companies] AS b
ON i.concom = b.company COLLATE sql_latin1_general_cp1_ci_as
INNER JOIN timelog AS t
ON t.inquiry_id = i.inquiry_id
INNER JOIN prod AS p
ON i.prod_id = p.prod_id
INNER JOIN category AS c
ON p.category_id = c.category_id
WHERE ( Datepart(yyyy, escdate) = 2011 )
GROUP BY i.concom,
b.company,
b.priority
ORDER BY totalwithoutnew DESC,
b.priority DESC
You should split the query to avoid multiple results from tbl_companies.
select distinct b.company,
b.priority,
x.concom,
x.totalwithoutnew,
x.totalallid
FROM (
SELECT i.concom,
Coalesce (SUM(CASE
WHEN c.category_id = '30' THEN 0
ELSE t.logmins
END), 0) AS totalwithoutnew,
Coalesce (SUM(t.logmins), 0) AS totalallid
FROM helpdesk3.dbo.inquiry AS i
INNER JOIN timelog AS t
ON t.inquiry_id = i.inquiry_id
INNER JOIN prod AS p
ON i.prod_id = p.prod_id
INNER JOIN category AS c
ON p.category_id = c.category_id
WHERE ( Datepart(yyyy, escdate) = 2011 )
GROUP BY i.concom
) x
INNER JOIN [Check].[dbo].[tbl_companies] AS b
ON x.concom = b.company COLLATE sql_latin1_general_cp1_ci_as
ORDER BY x.totalwithoutnew DESC,
b.priority DESC
Your join from the INQUIRY table to the tbl_companies table is going to generate a set of three rows (when there are three companies) so the next join to the TIMELOG table is also going to have three values for each TIMELOG.LOGMINS column - therefore it follows that the COALESCE (SUM(CASE WHEN C.CATEGORY_ID = '30' THEN 0 ELSE t.LOGMINS END), 0) AS TotalWithoutNew calculation will be tripled.
select
...
FROM helpdesk3.dbo.INQUIRY AS i
inner join [Check].[dbo].[tbl_companies] As B ON i.CONCOM = B.company COLLATE SQL_Latin1_General_CP1_CI_AS
INNER JOIN TIMELOG AS t ON t.INQUIRY_ID = i.INQUIRY_ID
...
If you want a single company to appear in the select and not multiply up the sum remove the join to tbl_companies from the where clause and the group by clause. Something along these lines should work (although without knowing the exact structure of the data I can't be certain):
select
(select company from [tbl_companies] where company = i.concom) as company,
(select priority from [tbl_companies] where company = i.concom) as priority,
...
FROM helpdesk3.dbo.INQUIRY AS i
INNER JOIN TIMELOG AS t ON t.INQUIRY_ID = i.INQUIRY_ID
...
There are a couple of ways of doing this. Assuming that priority, company and externalip uniquely identify tbl_companies records, I suggest:
SELECT b.company,
b.priority,
i.concom,
Coalesce (SUM(CASE
WHEN c.category_id = '30' THEN 0
ELSE t.logmins
END), 0) / COUNT(DISTINCT b.externalip) AS totalwithoutnew,
Coalesce (SUM(t.logmins), 0) / COUNT(DISTINCT b.externalip) AS totalallid
FROM helpdesk3.dbo.inquiry AS i
INNER JOIN [Check].[dbo].[tbl_companies] AS b
ON i.concom = b.company COLLATE sql_latin1_general_cp1_ci_as
INNER JOIN timelog AS t
ON t.inquiry_id = i.inquiry_id
INNER JOIN prod AS p
ON i.prod_id = p.prod_id
INNER JOIN category AS c
ON p.category_id = c.category_id
WHERE ( Datepart(yyyy, escdate) = 2011 )
GROUP BY i.concom,
b.company,
b.priority
ORDER BY totalwithoutnew DESC,
b.priority DESC

Why am I getting "Unknown Column" error?

The exact error I am getting is: "Unknown column 'trans_paid' in 'where clause'"
My query ($from_date and $to_date are correctly formatted):
SELECT
o.order_id,
o.order_po_no,
o.order_ship_date,
acct.acct_company,
SUM( ROUND( i.item_qty * i.item_price, 2 ) ) AS item_amount, (
SELECT SUM( trans_amount )
FROM transactions
WHERE order_id = o.order_id
AND trans_pending =0
AND trans_date >= '$from_date'
AND trans_date <= '$to_date'
) AS trans_paid
FROM orders AS o
INNER JOIN accounts AS acct ON o.acct_id = acct.acct_id
INNER JOIN items AS i ON o.order_id = i.order_id
WHERE (o.order_status =7 or o.order_status = 4)
AND trans_paid IS NOT NULL
AND acct.is_wholesale =1
AND acct.acct_company LIKE '%".$_POST['company']."%'
GROUP BY o.order_id
You can't reference aliased columns in the SELECT cause from the WHERE clause. You'll have to wrap it in a subquery if you want to filter on it.
Standard SQL doesn't allow you to refer to aggregate columns in the WHERE clause. You need to move the trans_paid condition to a HAVING clause to make it work.
Change
WHERE (o.order_status =7 or o.order_status = 4)
AND trans_paid IS NOT NULL
AND acct.is_wholesale =1
AND acct.acct_company LIKE '%".$_POST['company']."%'
GROUP BY o.order_id
to
WHERE (o.order_status =7 or o.order_status = 4)
AND acct.is_wholesale =1
AND acct.acct_company LIKE '%".$_POST['company']."%'
GROUP BY o.order_id
HAVING trans_paid IS NOT NULL
An alias name to be used in the Where clause has to be declared in the FROM clause...You simply renamed a column not actually rename an object such as a table.
use this query:
SELECT
o.order_id,
o.order_po_no,
o.order_ship_date,
acct.acct_company,
SUM( ROUND( i.item_qty * i.item_price, 2 ) ) AS item_amount,
trans_paid
FROM orders AS o
LEFT JOIN
(SELECT SUM( trans_amount ) AS trans_paid
FROM
WHERE trans_pending =0
AND trans_date >= '$from_date'
AND trans_date <= '$to_date'
) temp
USING order_id
INNER JOIN accounts AS acct ON o.acct_id = acct.acct_id
INNER JOIN items AS i ON o.order_id = i.order_id
WHERE (o.order_status =7 or o.order_status = 4)
AND trans_paid IS NOT NULL
AND acct.is_wholesale =1
AND acct.acct_company LIKE '%".$_POST['company']."%'
GROUP BY o.order_id