I am trying to write a query where I want to sum a price column based on the condition which is a subquery.
my query :
select
fund.FundName,
SUM(Case when (
Select Top 1 bitValue
from table 1
where table1.id = Company.id and table1.field = 25
) = 1 then price else 0 end) as 'TotalPrice'
from
Fund left outer join Company on Company.fundId=fund.id
group by
fund.fundName
It throws me error : Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
What is the best alternative way to achieve this.
Hope this Works for your Case:
SELECT
FUND.FUNDNAME,
S.TotalPrice
FROM FUND
LEFT OUTER JOIN COMPANY ON COMPANY.FUNDID=FUND.ID
LEFT JOIN (SELECT CASE WHEN BITVALUE=1 THEN SUM(PRICE) ELSE 0 END as 'TotalPrice',table1.ID
from table 1
where table1.id = Company.id and table1.field = 25 GROUP BY table1.ID
) S ON S.ID=Company.id
GROUP BY
FUND.FUNDNAME
untested obviously with no sample data provided.
select fund.FundName
,SUM(Case when table1.id is not null then price else 0 end) as 'TotalPrice'
from Fund
left outer join Company on Company.fundId = fund.id
left outer join (
select distinct id
from table1
where field = 25
and bitvalue = 1
) table1 on table1.id = Company.id
group by fund.fundName
Related
I have 2 tables Table1 and Table2 in which I want to get the total count of duplicate rows:
Expected output:
Query tested:
SELECT
t1.name,
t1.duplicates,
ISNULL(t2.active, 0) AS active,
ISNULL(t3.inactive, 0) AS inactive
FROM
(SELECT
t1.name, COUNT(*) AS duplicates
FROM
(SELECT c.name
FROM table1 c
INNER JOIN table2 as cd on cd.id = c.id)) t1
GROUP BY
name
HAVING
COUNT(*) > 1) t1
LEFT JOIN
(SELECT c.name, COUNT(*) AS active
FROM table1 c
WHERE name IN (SELECT c.name FROM table1 c)
GROUP BY c.name AND status = 'Active'
GROUP BY name) t2 ON t1.name = t2.name
LEFT JOIN
(SELECT c.name, COUNT(*) AS inactive
FROM table1 c
WHERE name IN (SELECT c.name FROM table1 c GROUP BY c.name)
AND status = 'InActive'
GROUP BY name) t3 ON t1.name = t3.name
ORDER BY
name
It is still returning duplicate rows and I'm unable to get the id and creator column
If you would pardon subquery and left join, i'd suggest the following query:
select b.*,
count(creator) as creator_count
from
(select a.mainid,
a.name,
sum(case when a.status = "active"
then 1 else 0 end) as active_count,
sum(case when a.status = "inactive"
then 1 else 0 end) as inactive_count,
count(a.name) as duplicate_count
from table1 as a
group by a.name
having count(a.name) > 1) as b
left join table2 as c
on b.mainid = c.mainid
group by c.mainid
having count(c.creator) > 1
rather than forcing our way to join the two table directly. First, derive the information we can get from the Table1 then join it with the Table2 to get the creator count.
SQL Fiddle: http://sqlfiddle.com/#!9/4daa19e/28
I have the below SQL query that is attempting to return the Last Transaction date for a specific part. The subquery that I'm left joining runs fine when I run it by itself (with the part specific criteria)
SELECT TOP 1 S1.*
FROM PartTran S1
WHERE S1.TranDate > '10/10/2016' AND S1.TranType <> 'ADJ-CST' AND S1.PartNum = '0000AAAO' ORDER BY S1.TranDate DESC
However when I join this into my main query, its returning null.
SELECT T1.PartNum, T2.TranDate, T2.TranType
FROM dbo.Part T1
LEFT JOIN (SELECT TOP 1 S1.* FROM PartTran S1 WHERE S1.TranDate > '10/10/2016' AND S1.TranType <> 'ADJ-CST' ORDER BY S1.TranDate DESC) T2 ON T1.Company = T2.Company AND T1.PartNum = T2.PartNum
WHERE T1.PartNum = '0000AAAO'
Am I missing something here?
Can you please check this following query-
SELECT
T1.PartNum,
T2.TranDate,
T2.TranType
FROM dbo.Part T1
LEFT JOIN
(
SELECT TOP 1 S1.*
FROM PartTran S1
WHERE S1.TranDate > '10/10/2016'
AND S1.TranType <> 'ADJ-CST'
AND S1.PartNum = '0000AAAO'
-- I think this above filter (AND S1.PartNum = '0000AAAO') is required
-- other wise top 1 can select records belongs to other PartNum and
-- your left join will return NULL logically
ORDER BY S1.TranDate DESC
) T2 ON T1.Company = T2.Company
AND T1.PartNum = T2.PartNum
WHERE T1.PartNum = '0000AAAO';
The reason why your original query doesn't work has to do with order of operations.
The derived table T2 resulted in 1 and only 1 record; not 1 record per PART number. This has to do with the derived table obtaining it's results BEFORE it can be joined to T1. Since the part numbers didn't match unless you got lucky on the part and day and company... you would get no data. A cross/outer apply allows you to get the TOP record per Join Criteria. and thus will return multiple records; 1 for each part and company; instead of just 1.
I think you're after a cross or outer apply and you can avoid the 2nd filter in the derived table (T2) If you want parts w/o any transactions kept then use the outer apply, if you only want those with part transactions use cross apply.
SELECT T1.PartNum, T2.TranDate, T2.TranType
FROM dbo.Part T1
CROSS APPLY (SELECT TOP 1 S1.*
FROM PartTran S1
WHERE S1.TranDate > '10/10/2016'
AND S1.TranType <> 'ADJ-CST'
ORDER BY S1.TranDate DESC) T2
ON T1.Company = T2.Company
AND T1.PartNum = T2.PartNum
WHERE T1.PartNum = '0000AAAO'
Alternatively you could use a row number instead of top and partition by your company and partNum ordering by transdate and only return row number 1st ordering by your transdate descending.
Here's a MSDN Doc link showing how cross/outer apply
works.
Try removing the 'LEFT' in your join because it is allowing you to select rows in the sub query that don't meet the criteria of your WHERE clause. That seemed to fix the issue in my text environment at least.
I would suggest a simpler query:
SELECT TOP 1 p.PartNum, T.TranDate, T.TranType
FROM dbo.Part p JOIN
PartTran pt
ON pt.Company = p.Company AND
pt.PartNum = t.PartNum AND
pt.TranType <> 'ADJ-CST' AND
pt.TranDate > '2016-10-10'
WHERE p.PartNum = '0000AAAO'
ORDER BY pt.TranDate DESC;
I have a query as follows:
select --this select should always give me 1 record
tbl1.Id, tbl1.Name, tbl1.Address, tbl2.relNo,
CASE WHEN tbl3.Comments IS NOT NULL THEN 1 ELSE 0 END AS 'Required'
from
table1 tbl1
inner join
table2 tbl2 on tbl2.Id = tbl1.Id
left join -- This left join table gives me 5 records for one instance
(select
R.Id, C.Comments
from
tblC C
inner join
tblR R on R.Id = C.id) tbl3 on tbl3.Id = tbl2.Id
I want to write a CASE statement on the rows my left join is giving to check for null value as above and my final select query always return only 1 row. Is there a way to check if all five Comments Column values from my left join be checked for NULLs in the above query?
I would take a shortcut an use a COUNT() OVER PARTITION
CASE WHEN COUNT(*) OVER (PARTITION BY tbl3.Id) =0 THEN 0 ELSE 1 END AS 'Required'
You would have to DISTINCT your output above. Another option would be to GROUP BY and filter in the HAVING clause.
select --this select should always give me 1 record
tbl1.Id, tbl1.Name, tbl1.Address, tbl2.relNo
From table1 tbl1
inner join table2 tbl2 on tbl2.Id = tbl1.Id
left join (-- This left join table gives me 5 records for one instance
SELECT R.Id,
C.Comments
FROM tblC C
INNER JOIN tblR R on R.Id = C.id
) tbl3 on tbl3.Id = tbl2.Id
GROUP BY
Id, Name, Address, relNo
HAVING
COUNT(*) = 5
Is this what you're looking for?
(CASE WHEN (select count(tbl3.id) FROM tbl3 WHERE tbl3.Comments IS NULL) then 1 else 0 end) as 'RequiredVal'
select --this select should always give me 1 record
tbl1.Id, tbl1.Name, tbl1.Address, tbl2.relNo,
CASE WHEN tbl3.Comments IS NOT NULL THEN 1 ELSE 0 END AS 'Required'
, (CASE WHEN (select count(tbl3.id) FROM tbl3 WHERE tbl3.Comments IS NULL) then 1 else 0 end) as 'RequiredVal'
From table1 tbl1
inner join table2 tbl2 on tbl2.Id = tbl1.Id
left join (-- This left join table gives me 5 records for one instance
SELECT R.Id,
C.Comments
FROM tblC C
INNER JOIN tblR R on R.Id = C.id
) tbl3 on tbl3.Id = tbl2.Id
I have 4 tables in a database. The warehouse contains boxes owned by clients, and the boxes have files in them. There is a Client table, a Warehouse table, a Boxes table, and a Files table.
So the Client table has WarehouseID as a foreign key, the Boxes table has ClientID as a foreign key, and the Files table has BoxID as a foreign key. I want to count the number of boxes and files that each client has in my query, as well as the number of boxes that are in and out of the warehouse. A Status field on the Boxes and Files tables determines if the boxes and files are in or out of the warehouse. I run the following query on the boxes and the numbers are correct:
SELECT
[c].[ClientID],
[c].[Name] AS [ClientName],
[w].[Name] AS [WarehouseName],
COUNT(DISTINCT [b].[BoxID]) AS [BoxCount],
SUM(CASE WHEN [b].[Status] = #IN THEN 1 ELSE 0 END)) AS [BoxesIn],
SUM(CASE WHEN [b].[Status] = #OUT THEN 1 ELSE 0 END) AS [BoxesOut],
SUM(CASE WHEN [b].[DestructionDate] <= GETDATE() THEN 1 ELSE 0 END) AS [BoxesForDestruction],
FROM [Clients] AS [c] INNER JOIN [Boxes] AS [b]
ON [c].[ClientID] = [b].[ClientID]
INNER JOIN [Warehouses] AS [w]
ON [c].WarehouseID = [w].[WarehouseID]
WHERE [c].[ClientID] = #ClientID
GROUP BY
[c].[ClientID],
[c].[Name],
[w].[Name]
This produces the output of:
ClientID | ClientName | WarehouseName | BoxCount | BoxesIn | BoxesOut | BoxesForDestruction
1 | ACME Corp. | FooFactory | 22744 | 22699 | 45 | 7888
The output of the count is correct. When I add the Files table to the INNER JOIN then the numbers get inflated. Here is the SQL:
SELECT
[c].[ClientID],
[c].[Name] AS [ClientName],
[w].[Name] AS [WarehouseName],
COUNT(DISTINCT [b].[BoxID]) AS [BoxCount],
COUNT(DISTINCT [f].[FileID]) AS [FileCount], -- *NEW*
SUM(CASE WHEN [b].[Status] = #IN THEN 1 ELSE 0 END)) AS [BoxesIn],
SUM(CASE WHEN [b].[Status] = #OUT THEN 1 ELSE 0 END) AS [BoxesOut],
SUM(CASE WHEN [b].[DestructionDate] <= GETDATE() THEN 1 ELSE 0 END) AS [BoxesForDestruction],
FROM [Clients] AS [c] INNER JOIN [Boxes] AS [b]
ON [c].[ClientID] = [b].[ClientID]
INNER JOIN [Warehouses] AS [w]
ON [c].[WarehouseID] = [w].[WarehouseID]
INNER JOIN [Files] AS [f] -- *NEW*
ON [b].[BoxID] = [f].[BoxID] -- *NEW*
WHERE [c].[ClientID] = #ClientID
GROUP BY
[c].[ClientID],
[c].[Name],
[w].[Name]
This gives me the count output below (I've omitted the first 3 columns since they're not relevant):
BoxCount | FilesCount | BoxesIn | BoxesOut | BoxesForDestruction
19151 | 411961 | 411381 | 580 | 144615
The FilesCount is correct, but the other numbers are off. I know why this is happening, but I'm not sure how to fix it. The extra rows are created due to the multiple rows returned by the join on the boxes and files. When performing the SUM, the extra rows inflate the count. Since there is only one row for the warehouse, that join doesn't affect the count. How do I modify my query to get the correct number of files and boxes in and out of the warehouse?
A join repeats each row in the left hand table for each row in the right hand table. If you combine multiple joins some rows will be double counted. A solution is to move the count to a subquery. For example:
select *
from table1 t1
join (
select table1_id
, count(*)
from table2
group by
table1_id
) t2
on t2.table1_id = t1.id
join (
select table1_id
, count(*)
from table3
group by
table1_id
) t3
on t3.table1_id = t1.id
As mentioned by Andomar, I included "as myColumnOne" and "myColumnTwo" besides Count(*), as it is required on SQL Server 2018:
select *
from table1 t1
join (
select table1_id
, count(*) as myColumnOne
from table2
group by
table1_id
) t2
on t2.table1_id = t1.id
join (
select table1_id
, count(*) as myColumnTwo
from table3
group by
table1_id
) t3
on t3.table1_id = t1.id
I have a query inside a stored procedure that count some record inside a table:
SELECT
t_Supporter.supporterID,
COUNT(t_ticket.ticketID) AS totalTicket
FROM t_Supporter
INNER JOIN t_ticket
ON t_Supporter.supporterID = t_ticket.supporterID_FK
WHERE (t_Supporter.orgSectionID_FK = #orgID)
GROUP BY t_Supporter.supporterID
How can I make my query return zero if t_Supporter.supporterID have no record in t_ticket.
You need to change your COUNT to SUM with conditional aggregation and your INNER JOIN to a LEFT OUTER
SELECT t_Supporter.supporterID, SUM(CASE WHEN t_ticket.ticketID IS NOT NULL THEN 1 ELSE 0 END) AS totalTicket
FROM t_Supporter LEFT OUTER JOIN
t_ticket ON t_Supporter.supporterID = t_ticket.supporterID_FK
WHERE (t_Supporter.orgSectionID_FK = #orgID)
GROUP BY t_Supporter.supporterID