MySQL Joining tables and pulling information to check - mysql

I am trying to return a descending list of item types sold within a specified date range.
I understand how to get the amount of Item types and count them, but am stuck with how to link to the other tables. I will put my working code along with psuedo of how I think it needs to be done, any help would be greatly appreciated.
SELECT Item_Type, COUNT(*) as theAmount
FROM myDB.Item
//LINK order_ID to item
//WHERE order_ID includes Item_Type
//Link to session
//Find Ses_Date that order was made
GROUP BY Item_Type
ORDER BY theAmount desc
LIMIT 10
I have three tables I need to pull data from, the fields needed are shown:
Item
PK: Item_ID
Row: Item_Type
FK: Order_ID
Order
PK: Order_ID
FK: Session_ID
Session
PK: Ses_ID
Row: Ses_date

SELECT Item_Type, COUNT(*) as theAmount, Session_date
FROM Item
left outer join Order
on Item.Order_id = Order.Order_id
left outer join Session
on Order.Session_id = Session.Session_id
GROUP BY Item_Type
ORDER BY theAmount desc
LIMIT 10
The above query will give you the results.

SELECT i.Item_Type, COUNT(i.Item_Type) as theAmount
FROM Item AS i
JOIN Order AS o ON o.order_ID = i.Order_ID
JOIN Session AS s ON s.Ses_ID = o.Session_ID
WHERE s.Ses_date between #date1 AND #date2
GROUP BY i.Item_Type
ORDER BY theAmount DESC
LIMIT 10

you need to use LEFT JOIN in this case so if you have no matching records on the other table, the value for Item_Type would be zero.
SELECT a.Item_Type, COUNT(c.Ses_ID) theAmount
FROM Item a
LEFT JOIN `Order` b
ON a.Order_ID = b.Order_ID
LEFT JOIN `Session` c
ON b.Session_ID = c.Ses_ID
GROUP BY a.Item_Type
-- ORDER BY theAmount DESC
-- LIMIT 10

Related

How to retrieve top N rows from each group in SQL with JOIN tables

I need a database with two tabels. I need to JOIN them, group the records and then display top 5 rows from each group. Here is my initial query without top N records:
SELECT customerId, itemId, count(itemId) as num FROM Orders JOIN OrderItems ON orderId=orderId ORDER BY num DESC GROUP BY customerId
I suppose I would need a ROWNUM and PARTITION BY here, but I have no idea how to combine them with JOIN tables. Could you please help me?
To retrieve the top 5 rows per group in your query, you can use a subquery with the ROW_NUMBER function and a PARTITION BY clause.
SELECT customerId, itemId, num
FROM (
SELECT customerId, itemId, num,
ROW_NUMBER() OVER (PARTITION BY customerId ORDER BY num DESC) as rn
FROM (
SELECT customerId, itemId, count(itemId) as num
FROM Orders
JOIN OrderItems ON Orders.orderId = OrderItems.orderId
GROUP BY customerId, itemId
) as subquery1
) as subquery2
WHERE rn <= 5;
If you want to display the 5 orders with the most items, you could use this:
SELECT TOP 5
o.orderID, count(*)
FROM Order o INNER JOIN OrderItem oi on o.OrderID = oi.OrderID
GROUP BY o.OrderID
ORDER BY count(*) DESC
For displaying the top 5 items in each order, it is a bit more complex, because you cannot use windowed functions in WHERE or ORDER BY.
For this, you need a subquery to retrieve the ranking and sort/filter the result.
SELECT *
FROM
(
SELECT
oi.*,
ROW_NUMBER() OVER (PARTITION BY oi.OrderID ORDER BY oi.Something) as ranking
FROM OrderItem oi
) tmp WHERE ranking < 6
ORDER BY tmp.OrderID, tmp.ranking
If that is not your intent, please give an example for your intended result.

How to get first value from this sql query

Im trying to get by subquery clientId of customer with most orders but only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
SELECT a.ClientName
FROM Clients as a
INNER JOIN Orders as b
ON a.Id=b.ClientId
WHERE b.ClientId
IN(SELECT b.ClientId,COUNT( b.ClientId) as MAKS FROM Orders as b
GROUP BY b.ClientId ORDER BY MAKS DESC)
Do we have some tools to handle this and how can i optimize this query? Thanks in advance.
You don't really need the inner join because you are asking for an ID that is the same in both tables,
SELECT ClientName FROM Clients
WHERE Id = (SELECT TOP 1 ClientId FROM Orders
GROUP BY ClientId
ORDER BY COUNT(ClientId) DESC)
Using Top 1, Count and Group By
SQL Server
SELECT Top 1 a.ClientName , count(b.orders_id) TotalOrders
FROM Clients as a
INNER JOIN Orders as b
ON a.Id=b.ClientId
GROUP BY a.client_name
order by TotalOrders desc
MySQL
SELECT a.ClientName , count(b.orders_id) TotalOrders
FROM Clients as a
INNER JOIN Orders as b
ON a.Id=b.ClientId
GROUP BY a.client_name
order by TotalOrders desc
LIMIT 1

MySQL subquery limit 1

I have an sql query that returns a list of residential units, and a subquery that is supposed to get the last entered bill for that unit.
However when I add LIMIT 1 to the subquery, no bill entries are returned? If I leave it out, I get duplicate unit rows depending on the number of bill for the unit.
select * from unit u
left join (select id as billId, unit_id, added_on, end_reading, bill_type from bills
order by id desc) b ON unit_id = u.id
where community_Id = 1
and unit_section = 7
and unit_floor in (1,2,3,4,5)
order by unit_floor, display_order asc;
Anyone know how I can the subquery result limited to 1 bill?
When using joins that duplicate your results, add a group by statement. It's an alternative of the distinct from a simple select
select * from unit u
left join (select id as billId, unit_id, added_on, end_reading, bill_type from bills
order by id desc) b ON unit_id = u.id
where community_Id = 1
and unit_section = 7
and unit_floor in (1,2,3,4,5)
group by u.id
order by unit_floor, display_order asc;
Think you will need a sub query to get the first (lowest) id for each unit_id from the bills table. Then use that to join between the unit and bills table, getting the other matching columns from bills for that lowest id
SELECT u.*, bills.*
FROM unit u
LEFT OUTER JOIN
(
SELECT unit_id, MIN(id) AS min_id
FROM bills
GROUP BY unit_id
) b ON b.unit_id = u.id
LEFT OUTER JOIN bills
ON b.unit_id = bills.unit_id
AND b.min_id = bills.id
WHERE u.community_Id = 1
AND u.unit_section = 7
AND u.unit_floor in (1,2,3,4,5)
ORDER BY u.unit_floor, u.display_order asc;

MySQL: SELECT if non of group by members is equal to x

I have troubles getting proper data.
I have table structure like:
id INT(11) AI
order_id INT(11)
status varchar(45)
This table log status changes for orders.
So order_id's will have few statuses.
Now I need to select rows and group them by order_id, where order never had status (not even one status with given order_id) != 'example'
We don't show orders, where one of members had status = example
Sample data
1 12 ready
1 12 example
2 13 ready
2 13 sent
So I don't want order 12 to show at all, because one of it members have "example" status
I've tried grouping results, but it's not enough.
you can do it by simple join query :
select a.order_id
from ordrstatus as a left outer join (select orderid , count(*) as status from orderstatus where status = 'example' group by orderid) as b on a.orderid = b.orderid
where b.status = 0 or b.status is NUll
Join query always run faster then IN query . by using Join in query it will run only one time .
You can try like this...it will return all order id which never had status -example
Select
Order_id,
from TableName A where Not Exists(
Select id from TableName B where
status='example' and
a.Order_id=b.Order_id
)
group by Order_id
Not quite sure if you want the records for order which have had a status of example, or ones which have never had a status of example
To get a list of orders (with the status grouped up) which have had a status of example:-
SELECT a.order_id, GROUP_CONCAT(a.status)
FROM SomeTable a
INNER JOIN
(
SELECT order_id, COUNT(*)
FROM SomeTable
WHERE status = 'example'
GROUP BY order_id
) b
ON a.order_id = b.order_id
GROUP BY order_id
To get those which have NEVER had a status of exmaple
SELECT a.order_id, GROUP_CONCAT(a.status)
FROM SomeTable a
LEFT OUTER JOIN
(
SELECT order_id, COUNT(*)
FROM SomeTable
WHERE status = 'example'
GROUP BY order_id
) b
ON a.order_id = b.order_id
WHERE b.order_id IS NULL
GROUP BY order_id
EDIT
SELECT a.order_id, GROUP_CONCAT(a.status)
FROM SomeTable a -- Statuses
LEFT OUTER JOIN
(
SELECT order_id, COUNT(*)
FROM SomeTable
WHERE status = 'example'
GROUP BY order_id
) b -- Get any order id which has had a status of example (as a LEFT JOIN)
ON a.order_id = b.order_id
INNER JOIN
(
SELECT order_id, MAX(id) AS Latestid
FROM SomeTable
GROUP BY order_id
) c -- Get the latest status for each order (ie, max id)
ON a.order_id = c.order_id
LEFT OUTER JOIN
(
SELECT order_id, id
FROM SomeTable
WHERE status = 'example2'
) d -- Get the id of the order status of example2
ON a.order_id = d.order_id AND c.Latestid = d.id -- join on the same order id and that the record id matches the latest record id
WHERE b.order_id IS NULL -- reject those where a match was found on example for any status
AND d.order_id IS NULL -- reject those where a match was found on example2 for the latest status
GROUP BY order_id
try this
SELECT Order_ID FROM tbl_Orders
WHERE Status NOT IN ('example')
GROUP BY Order_ID
SELECT DISTINCT x.order_id
FROM order_status x
LEFT
JOIN order_status y
ON y.order_id = x.order_id
AND y.status = 'example'
WHERE y.id IS NULL;

MySQL DELETE statement with a join, HAVING and GROUP BY

I have a table of items and another of reports. Each report has a foreign key linking to an item being reported.
I am trying to delete all items displayed in this query:
SELECT items.id, title, SUM(weight) AS total_weight, SUM(weight)*10/views AS score
FROM items, reports
WHERE items.id = reports.item_id
GROUP BY items.id
HAVING score >= 50;
Trying something like this:
DELETE items
FROM (SELECT items.id, title, SUM(weight) AS total_weight, SUM(weight)*10/views AS score
FROM items, reports
WHERE items.id = reports.item_id
GROUP BY items.id
HAVING score >= 50)
AS T;
Gives me this error message:
ERROR 1109 (42S02): Unknown table 'items' in MULTI DELETE
In MySQL, you have to be careful about the subqueries. I think the following works:
DELETE FROM items
WHERE id IN (select *
from (SELECT items.id
FROM items join reports
on items.id = reports.item_id
GROUP BY items.id
HAVING SUM(weight)*10/views >= 50
)
)
It tricks the compiler into accepting the query by using an additional subquery. I also fixed your join syntax.
The following, though, rewrites the query into a more common syntax, using a correlated subquery:
delete from items
where exists (select r.item_id
from reports r
where r.item_id = items.item_id
group by r.item_id
having SUM(r.weight)*10/items.views >= 50
)
This is guessing that weight and views come from reports. Otherwise, you need to put theitems` alias in front instead.
DELETE FROM items
WHERE
id IN (
SELECT
items.id
FROM items, reports
WHERE items.id = reports.item_id
GROUP BY items.id
HAVING SUM(weight)*10/views >= 50)
I believe your delete statement is wrong. It should be delete from tablename where [condition].
DELETE FROM items
WHERE
id IN (
Select T.id from (SELECT items.id, title, SUM(weight) AS total_weight, SUM(weight)*10/views AS score
FROM items, reports
WHERE items.id = reports.item_id
GROUP BY items.id
HAVING score >= 50) T)
Try this:
DELETE FROM items
WHERE id IN (SELECT id
FROM (SELECT i.id itemId, (SUM(weight) * 10 / views) score
FROM items i INNER JOIN reports r ON i.id = r.item_id
GROUP BY itemId HAVING score >= 50
) AS A
);