I have searched high and low and can't seem to get a way to do what I want. I have a table with some customers, some products and their relationships.
I want to count the amount of returned rows from this part of the query
SELECT id
FROM customer
WHERE customer.name = 'SMITH'
OR customer.name = 'JONES'
I also want to return the ids that match SMITH and JONES (or other customer names chosen). I want to use the count of the returned rows as a variable (denoted as #var). I only want to return the products, id, and count that match my variable.
My questions are:
Is there a way that this can be done in a single SQL query?
Is there a way to return the count as well as the values?
I don't want to have to throw this into a PHP script or the like.
SELECT x.pId, p.productdesc, count(x.dId) as count
FROM
(
SELECT DISTINCT cId, pId
FROM Client
WHERE cId IN
(
SELECT id
FROM customer
WHERE customer.name = 'SMITH'
OR customer.name = 'JONES'
)
)x
JOIN Products p ON x.pId = p.id
GROUP BY x.pId
HAVING count = #var
Thanks,
M
This is sort of a 'literal' answer to what your asked, as you can use subqueries in the having clause. However, with more information (sample data and expected result) there may be a better way of doing what you want.
select x.pid, p.productdesc, count(x.pid) as count
from (select distinct cl.cid, cl.pid
from client cl
join customer cu
on cl.cid = cu.id
where cu.name in ('SMITH', 'JONES')) x
join products p
on x.pid = p.id
group by x.pid, p.productdesc
having count(x.pid) = (select count(*)
from customer
where name in ('SMITH', 'JONES'))
Related
i have two tables
Companies
company_payments
each company is doing two types of payments vat and witholding_tax, i am doing following query which returns me company's last payments for the current year
SELECT * FROM companies c
JOIN ( SELECT MAX(id) max_id, company_id FROM company_payments )
c_max ON (c_max.company_id = c.id)
JOIN company_payments cp ON (cp.id = c_max.max_id)
WHERE
YEAR(cp.last_payment) = YEAR(CURDATE())
Below is the structure of my company_payments table
Now instead of returning one last payment i want to return last payment for payment type 'vat' and 'witholding_tax' both , if its not there would need an empty record ,
Could someone please advise me how can i achieve this
You can use a correlated subquery:
select cp.*
from company_payments cp
where cp.last_payment = (select max(cp2.last_payment)
from company_payments cp2
where cp2.company_id = cp.company_id and
cp2.payment_type = cp.payment_type
);
If you want to filter only on the most recent year, you can add the date filter to the outer query.
I am trying to get the data for the best 5 customers in a railway reservation system. To get that, I tried getting the max value by summing up their fare every time they make a reservation. Here is the code.
SELECT c. firstName, c.lastName,MAX(r.totalFare) as Fare
FROM customer c, Reservation r, books b
WHERE r.resID = b.resID
AND c.username = b.username
AND r.totalfare < (SELECT sum(r1.totalfare) Revenue
from Reservation r1, for_res f1, customer c1,books b1
where r1.resID = f1.resID
and c1.username = b1.username
and r1.resID = b1.resID
group by c1.username
)
GROUP BY c.firstName, c.lastName, r.totalfare
ORDER BY r.totalfare desc
LIMIT 5;
this throws the error:[21000][1242] Subquery returns more than 1 row
If I remove the group by from the subquery the result is:(its a tabular form)
Jade,Smith,1450
Jade,Smith,725
Jade,Smith,25.5
Monica,Geller,20.1
Rach,Jones,10.53
But that's not what I want, as you can see, I want to add the name 'Jade' with the total fare.
I just don't see the point for the subquery. It seems like you can get the result you want with a sum()
select c.firstname, c.lastname, sum(totalfare) as totalfare
from customer c
inner join books b on b.username = c.username
inner join reservation r on r.resid = b.resid
group by c.username
order by totalfare desc
limit 5
This sums all reservations of each client, and use that information to sort the resulstet. This guarantees one row per customer.
The query assumes that username is the primary key of table customer. If that's not the case, you need to add columns firstname and lastname to the group by clause.
Note that this uses standard joins (with the inner join ... on keywords) rather than old-school, implicit joins (with commas in the from clause: these are legacy syntax, that should not be used in new code.
This is a slight variant of the question I asked here
SQL Query for getting maximum value from a column
I have a Person Table and an Activity Table with the following data
-- PERSON-----
------ACTIVITY------------
I have got this data in the database about users spending time on a particular activity.
I intend to get the data when every user has spent the maximum number of hours.
My Query is
Select p.Id as 'PersonId',
p.Name as 'Name',
act.HoursSpent as 'Hours Spent',
act.Date as 'Date'
From Person p
Left JOIN (Select MAX(HoursSpent), Date from Activity
Group By HoursSpent, Date) act
on act.personId = p.Id
but it is giving me all the rows for Person and not with the Maximum Numbers of Hours Spent.
This should be my result.
You have several issues with your query:
The subquery to get hours is aggregated by date, not person.
You don't have a way to bring in other columns from activity.
You can take this approach -- joins and group by, but it requires two joins:
select p.*, a.* -- the columns you want
from Person p left join
activity a
on a.personId = p.id left join
(select personid, max(HoursSpent) as max_hoursspent
from activity a
group by personid
) ma
on ma.personId = a.personId and
ma.max_hoursspent = a.hoursspent;
Note that this can return duplicates for a given person -- if there are ties for the maximum.
This is written more colloquially using row_number():
select p.*, a.* -- the columns you want
from Person p left join
(select a.*,
row_number() over (partition by a.personid order by a.hoursspent desc) as seqnum
from activity a
) a
on a.personId = p.id and a.seqnum = 1
ma.max_hoursspent = a.hoursspent;
I need to write a SQL query that will return all order numbers that have more than just SKU ENROLL but should not return an order number where SKU ENROLL is the only SKU on the order.
In this example, this order would be included in the query results.
Order 1001, contains SKU ENROLL and SKU 688631.
In this example, this order would NOT be included in the query results.
Order 1003, contains SKU ENROLL
Important to note, when query results are returned they look like this
Here is what I've written thus far but I am not sure on the rest. I've taken feedback from everyone who has responded and tried to incorporate it but haven't had good results.
select VO.DistID, VO.FirstName, VO.LastName, VO.OrderNumber, Email, Quantity, Sku, OrderStatus FROM dbo.VwOrders AS VO INNER JOIN dbo.VwDistributor AS VD ON VO.DistID = VD.DistID INNER JOIN dbo.VwOrderLines AS VOL ON VO.OrderNumber = VOL.OrderNumber INNER JOIN dbo.VwInventory AS VI ON vol.ItemNumber = VI.InventoryNo AND VOL.Warehouse = VI.Warehouse WHERE Sku = 'ENROLL'
There are several different ways to do this. Here's one option using conditional aggregation:
select orderid
from yourtable
group by orderid
having max(case when sku = 'ENROLL' then 1 else 0 end) = 1
and max(case when sku != 'ENROLL' then 1 else 0 end) = 1
SQL Fiddle Demo
select OrderID from table where SKU = 'ENROLL' and OrderID in
(select distinct OrderID from table group by OrderID having count(*) > 1)
Explanation: the inner query will give you all orderId's that appears more than once in the table. what we do in the rest of the query is select all records that equals to 'enroll' + in the appear twice list
You can use exists subqueries:
select *
from tbl t
where exists (select 1 from tbl x where x.orderid = t.orderid and x.sku = 'ENROLL')
and exists (select 1 from tbl x where x.orderid = t.orderid and x.sku <> 'ENROLL');
Very interesting answers so far. I really enjoyed reading them. Here is one option from me.
SELECT t1.*
FROM (SELECT * FROM tbl WHERE SKU = 'ENROLL') t1
INNER JOIN (SELECT * FROM tbl WHERE SKU != 'ENROLL') t2
ON t1.OrderID = t2.OrderID
GROUP BY t1.OrderID
I build two tables one having all order with at least one SKU = 'ENROLL' and one for orders with at least one SKU different from 'ENROLL' and I join them to get ... well the cross section of them two. This is what you look for, right?
This is a query on the Sakila sample database. I'm not sure why COUNT is returning '1' for every row - I want it to count the number of customers in that country/city/postal_code combination.
SELECT country.country_id, country.country, city.city_id, city.city, address.postal_code, COUNT(*) AS 'Customer Count'
FROM address
INNER JOIN city ON city.city_id = address.city_id
INNER JOIN country ON country.country_id = city.country_id
INNER JOIN customer ON customer.address_id = address.address_id
GROUP BY country.country, city.city, address.postal_code
Any ideas on what I'm doing wrong?
Here is some of the output:
Because you are not getting multiple records per GROUP.
The COUNT() function returns the number of records that match the same GROUP BY.
Also this query doesn't seem to work since you're selecting ID's but not grouping on them.