Join two queries become one subquery - tsql

I want to ask how to combine these two queries become one subquery?
select c.CustomerName, A.Qty
from Customer c join (select s.CustomerID, pd.Date, s.Qty
from Period pd join Sales s on pd.TimeID = s.TimeID) A on c.CustomerID = A.CustomerID
where #Date = A.Date
and
select sum(case when (pd.Date between '2010-03-15' and #Date) then s.Qty else 0 end) as TotalQty
from Period pd full join Sales s on pd.TimeID = s.TimeID full join Customer c on s.CustomerID = c.CustomerID
group by c.CustomerName, c.CustomerID
They should result one table contains these following columns: CustomerName, Qty, and TotalQty. I've tried many ways but they didn't work at all. Really hope your help, thanks.

Answering your question assuming you are looking at the result as one row and not "column" :
select c.CustomerName, A.Qty,(select sum(case when (pd.Date between '2010-03-15' and #Date) then s.Qty else 0 end)
from Period pd full join Sales s on pd.TimeID = s.TimeID full join Customer c on s.CustomerID = c.CustomerID
group by c.CustomerName, c.CustomerID
) as TotalQty
from Customer c join (select s.CustomerID, pd.Date, s.Qty
from Period pd join Sales s on pd.TimeID = s.TimeID) A on c.CustomerID = A.CustomerID
where #Date = A.Date
If you still want the result as a single column , google "row to column transpose"

Related

Subqueries and Combining Queries together

I have a problem I've been working on. I've broken it down to a couple of steps below. I have trouble combining all the queries together to solve the following:
Find members who have spent over $1000 in departments that have
brought in more than $10000 total ordered by the members' id.
Schema:
departments(id, name)
products (id, name, price)
members(id, name, number, email, city, street_name, street_address)
sales(id, department_id, product_id, member_id, transaction_date
Step 1)
I found the departments that have brought in more than 10,000$
select s.department_id
from sales s join products p on
s.product_id = p.id
group by s.department_id
having sum(price) > '10000'
Step 2) I found the members and the departments that they shop in
select *
from members m
join sales s
on m.id = s.member_id
join departments d
on d.id = s.department_id
Step 3) I combined 1 and 2 to find members taht shop in departments that have brought in more than 10,000
select *
from members m
join sales s
on m.id = s.member_id
join departments d
on d.id = s.department_id
where s.department_id in
(select s.department_id
from sales s join products p on
s.product_id = p.id
group by s.department_id
having sum(price) > '10000')
Step 4) I found members and their id, email, total_spending > 1,000$
select m.id, m.name, m.email, sum(price) as total_spending
from members m join sales s on
m.id = s.member_id
join products p on
p.id = s.product_id
group by m.id
having sum(price) > '1000'
Step 5)
All of the steps work individually but when I put them together in my attempt:
select m.id, m.name, m.email, sum(price) as total_spending
from members m join sales s on
m.id = s.member_id
join products p on
p.id = s.product_id
where m.id in (select distinct m.id
from members m
join sales s
on m.id = s.member_id
join departments d
on d.id = s.department_id
where s.department_id in
(select s.department_id
from sales s join products p on
s.product_id = p.id
group by s.department_id
having sum(price) > '10000'))
group by m.id
having sum(price) > '1000'
The output is wrong. (This is on CodeWars) If someone could point me in the right direction that would be really great! Thank you.
Try to group by member_id and department_id:
select s.member_id,s.department_id,sum(p.price) as total_spending
from members m
join sales s on m.id = s.member_id
join products p on p.id = s.product_id
where s.department_id in (
select s.department_id
from sales s
join products p on s.product_id = p.id
group by s.department_id
having sum(p.price) > 10000 -- the departments which brought in more than $10000 total
)
group by s.member_id,s.department_id
having sum(p.price) > 1000 -- who have spent over $1000 in one department
And if you need you will able to calc how much spent each of members:
select member_id,sum(total_spending) total
from
(
-- the first query is here
) q
group by member_id

SUM(CASE WHEN ...) returns a greater number than COUNT(DISTINCT..)

I have written a query in two models, but I can't figure out why the second query returns a greater number than the first one; while the number that the first one, COUNT(DISTINCT...) returns is correct:
WITH types(id) AS (VALUES('{1, 4, 5, 3}'::INTEGER[])),
date_gen64 AS
(
SELECT CAST (generate_series(date '10/1/2017', date '11/15/2017', interval
'1 day') AS date) as days ORDER BY days)
SELECT cl.class_date AS c_date,
count(DISTINCT (CASE WHEN co.id = 1 THEN p.id END)),
count(DISTINCT (CASE WHEN co.id = 2 THEN p.id END))
FROM person p
JOIN envelope e ON e.personID = p.id
JOIN "class" cl on cl.id = p.classID
JOIN course co ON co.id = cl.course_id AND co.id = 1
JOIN types ON cr.type_id = ANY (types.id)
RIGHT JOIN date_gen64 dg ON dg.days = cl.class_date
GROUP BY cl.class_date
ORDER BY cl.class_date
The above query returns 26 but following query returns 27!
The reason why I rewrote it with SUM is that the first query
was too slow. But my question is that why the second one counts more?
WITH types(id) AS (VALUES('{1, 4, 5, 3}'::INTEGER[]))
SELECT tmpcl.days,
SUM(CASE WHEN tmp80.course_id = 1 THEN 1
ELSE 0 END),
SUM(CASE WHEN tmp80.course_id = 2 THEN 1
ELSE 0 END)
FROM (
SELECT CAST (generate_series(date '10/1/2017', date '11/15/2017',
interval '1 day') AS date) as days ORDER BY days) tmpcl
LEFT JOIN (
SELECT DISTINCT p.id AS "person_id",
cl.class_date AS c_date,
co.id AS "course_id"
FROM person p
JOIN envelope e ON e.personID = p.id
JOIN "class" cl on cl.id = p.classID
JOIN course co ON co.id = cl.course_id
JOIN types ON cr.type_id = ANY (types.id)
WHERE co.id IN ( 1 , 2 )
) tmp80 ON tmpcl.days = tmp80.class_date
GROUP BY tmpcl.days
ORDER BY tmpcl.days
You can theoretically have multiple people enrolled in the same class on the same day. Indeed that would seem to be the main point of having classes. So each time there are multiple people assigned to the same class on the same day you can have a higher count than you would in your first query. Does that make sense?
You don't appear to be using p.id in that inner query so simply remove it and your counts should match.
WITH types(id) AS (VALUES('{1, 4, 5, 3}'::INTEGER[]))
SELECT tmpcl.days,
SUM(CASE WHEN tmp80.course_id = 1 THEN 1
ELSE 0 END),
SUM(CASE WHEN tmp80.course_id = 2 THEN 1
ELSE 0 END)
FROM (
SELECT CAST (generate_series(date '10/1/2017', date '11/15/2017',
interval '1 day') AS date) as days ORDER BY days) tmpcl
LEFT JOIN (
SELECT DISTINCT cl.class_date AS c_date,
co.id AS "course_id"
FROM person p
JOIN envelope e ON e.personID = p.id
JOIN "class" cl on cl.id = p.classID
JOIN course co ON co.id = cl.course_id
JOIN types ON cr.type_id = ANY (types.id)
WHERE co.id IN ( 1 , 2 )
) tmp80 ON tmpcl.days = tmp80.class_date
GROUP BY tmpcl.days
ORDER BY tmpcl.days

Problems with Postgresql ERROR: subquery uses ungrouped column "ev.title" from outer query

I have a query like this:
select c.id, c.name, c.website, c.longdescription, c.description, c.email,
(SELECT jsonb_agg(ev) FROM
(SELECT ev.title, ev.description, ev.longdescription,
(SELECT jsonb_agg(ed) FROM
(SELECT ed.startdate, ed.enddate, ed.id WHERE ed.id notnull)ed) as dates, ev.id WHERE ev.id notnull) ev) as events,
(SELECT jsonb_agg(ca) FROM (SELECT ct.zip, ca.id, ca.street1, ca.street2, ca.addresstype_id, ST_Y(ca.geopoint::geometry) as latitude, ST_X(ca.geopoint::geometry) as longitude
WHERE ca.id notnull)ca) as addresses
FROM companies c
LEFT JOIN events ev ON ev.company_id = c.id
LEFT JOIN companyaddresses ca ON ca.company_id = c.id
LEFT JOIN cities ct ON ct.id = ca.city_id
LEFT JOIN eventdates ed ON ed.event_id = ev.id
GROUP by c.id
I am getting the error "ERROR: subquery uses ungrouped column "ev.title" from
outer query Position: 125".
Can't figure out how to group it correctly for the subqueries. Any suggestions?
Give this a try:
SELECT c.id, c.name, c.website, c.longdescription, c.description, c.email,
    (SELECT jsonb_agg(ev) FROM
        (SELECT even.title, even.description, even.longdescription,
            (SELECT jsonb_agg(ed) FROM
                (SELECT eventdates.startdate, eventdates.enddate, eventdates.id FROM eventdates WHERE eventdates.event_id = even.id)ed) as dates,
        even.id FROM events even WHERE even.company_id = c.id) ev) as events,
jsonb_agg((SELECT ca FROM (SELECT ct.zip, ca.id, ca.street1, ca.street2, ca.addresstype_id, ST_Y(ca.geopoint::geometry) as latitude, ST_X(ca.geopoint::geometry) as longitude WHERE ca.id notnull)ca)) as addresses
FROM companies c
LEFT JOIN companyaddresses ca ON ca.company_id = c.id
LEFT JOIN cities ct ON ct.id = ca.city_id
Group by c.id

SQL Join Statement Issue

I'm tring to grab all fields from the latest Cash record, and then all fields from the related TransactionInfo record. I can't quite get this to work yet:
select t.*, top 1 c.* from Cash c
inner join TransactionInfo t
on c.TransactionID = t.id
order by c.createdOn desc
select top 1 *
from Cash c
inner join TransactionInfo t on c.TransactionID = t.id
order by createdOn desc
What's that top 1 doing there? If you only want one row then the TOP(1) must come first:
SELECT TOP(1) t.*, c.*
FROM Cash c
INNER JOIN TransactionInfo t
ON c.TransactionID = t.id
ORDER BY c.createdOn DESC
select t.,c.
from (Select top 1 * from Cash order by createdOn desc
) c
inner join TransactionInfo t
on c.TransactionID = t.id
order by createdOn desc
DOn;t use select * especially with a join, it wastes server resources.
SELECT c.*, t.* FROM cash c, transactioninfo t
WHERE c.infoid = t.id AND c.createdOn = (SELECT max(createdOn) FROM cash WHERE infoId = t.id) ORDER BY transactiontabledate desc
You need to find the record with the latest date from the cash table for each transactionId and use that also to filter it out in your query.

Cannot perform an aggregate function on a subquery

Can someone help me with this query?
SELECT p.OwnerName, SUM(ru.MonthlyRent) AS PotentinalRent, SUM(
(SELECT COUNT(t.ID) * ru.MonthlyRent FROM tblTenant t
WHERE t.UnitID = ru.ID)
) AS ExpectedRent
FROM tblRentalUnit ru
LEFT JOIN tblProperty p ON p.ID = ru.PropertyID
GROUP BY p.OwnerName
I'm having problems with the second sum, it won't let me do it. Evidently SUM won't work on subqueries, but I need to calculate the expected rent (MonthlyRent if there is a tenant assigned to the RentalUnit's id, 0 of they're not). How can I make this work?
SELECT p.OwnerName, SUM(ru.MonthlyRent) AS PotentialRent, SUM(cnt) AS ExpectedRent
FROM tblRentalUnit ru
LEFT JOIN
tblProperty p
ON p.ID = ru.PropertyID
OUTER APPLY
(
SELECT COUNT(t.id) * ru.MonthlyRent AS cnt
FROM tblTenant t
WHERE t.UnitID = ru.ID
) td
GROUP BY p.OwnerName
Here's a test script to check:
WITH tblRentalUnit AS
(
SELECT 1 AS id, 100 AS MonthlyRent, 1 AS PropertyID
UNION ALL
SELECT 2 AS id, 300 AS MonthlyRent, 2 AS PropertyID
),
tblProperty AS
(
SELECT 1 AS id, 'Owner 1' AS OwnerName
UNION ALL
SELECT 2 AS id, 'Owner 2' AS OwnerName
),
tblTenant AS
(
SELECT 1 AS id, 1 AS UnitID
UNION ALL
SELECT 2 AS id, 1 AS UnitID
)
SELECT p.OwnerName, SUM(ru.MonthlyRent) AS PotentialRent, SUM(cnt) AS ExpectedRent
FROM tblRentalUnit ru
LEFT JOIN
tblProperty p
ON p.ID = ru.PropertyID
OUTER APPLY
(
SELECT COUNT(t.id) * ru.MonthlyRent AS cnt
FROM tblTenant t
WHERE t.UnitID = ru.ID
) td
GROUP BY p.OwnerName
What is the meaning of the sum of the unitMonthlyRent times the number of tenants, for some partiicular rental unit (COUNT(t.ID) * ru.MonthlyRent )?
Is it the case that all you are trying to do is see the difference between the total potential rent from all untis versus the expected rent (From only occcupied units) ? If so, then try this
Select p.OwnerName,
Sum(r.MonthlyRent) AS PotentinalRent,
Sum(Case t.Id When Null Then 0
Else r.MonthlyRent End) ExpectedRent
From tblRentalUnit r
Left Join tblTenant t
On t.UnitID = r.ID
left Join tblProperty p
On p.ID = r.PropertyID)
Group By p.OwnerName