MySql - Retrieving the last record in each subgroup - mysql

1.Purchase table
Id user pur_type
----------------------
1 408 5-12
2 408 5-12
3 222 1-11
4 222 5-12
5 408 1-11
6 408 1-11
2. goods table
Id parts days
-----------------
1 1-11 50
2 5-12 40
I implemented such query
SELECT p1.id, p1.user, p1.pur_type, g.parts, g.days
FROM purchase p1
INNER JOIN goods g ON p1.pur_type = g.parts
LEFT JOIN goods p2 ON ( p1.pur_type= p2.pur_type
AND p1.id < p2.id )
WHERE p2.id IS NULL
The result is only last record for each pur_type
Id user pur_type parts days
---------------------------------
4 222 5-12 5-12 40
6 408 1-11 1-11 50
How to get last record from purchase table of each pur_type for one specific user?
for example for user 408 need result:
Id user parts days
-------------------------
2 408 5-12 40
6 408 1-11 50
Result explanation:
last record fot part 5-12 for user 408 is id=2
last record for part 1-11 for user 408 is id=6

SELECT a.*, c.* -- select columns youw ant
FROM Purchase a
INNER JOIN
(
SELECT user, MAX(ID) max_ID
FROM Purchase
GROUP BY user, pur_type
) b ON a.user = b.user AND
a.ID = b.max_ID
INNER JOIN goods c
ON a.pur_type = c.parts
WHERE a.USER = 408
SQLFiddle Demo
for better performance, add an INDEX on column parts on table goods as well on pur_type

A simple modification to the existing query:
SELECT p1.id, p1.user, p1.pur_type, g.parts, g.days
FROM purchase p1
INNER JOIN goods g ON p1.pur_type = g.parts
LEFT JOIN purchase p2
ON ( p1.pur_type= p2.pur_type AND p1.id < p2.id AND p1.user=p2.user)
WHERE p2.id IS NULL and p1.user = 408

Related

How to display only the rows where number of unique values in one column equals value in second column

(Using mysql 5.0)
I have this table:
opportunity main_user_id certificate_id required_certificates
1 491 1 2
1 341 1 2
1 161 1 2
1 161 2 2
1 205 2 2
1 578 2 2
2 161 2 2
2 466 3 2
2 466 2 2
2 156 2 2
2 668 2 2
3 222 5 1
3 123 5 1
3 875 5 1
3 348 5 1
I need to only display the rows where number of distinct values in certificate_id equals value in required_certificates.
opportunity_id column has id's from 0 to 15 and main_user_id's repeat (hence I can't use group by)
The table is basically a list of users matched for particular job opportunity, who have the required certificates. All i need to do now, is to only show the ones who have both of the required certificates, not one OR another.
My current sql statement:
select op_main.id as opportunity_id, u.id as main_user_id, c.id as certificate_id, required2.required as required_certificates
from opportunities as op_main
join opportunity_certificates as oc on oc.opportunity_id = op_main.id
join certificates as c on c.id = oc.certificate_id and oc.is_required
join user_certificates as uc on uc.certificate_id = c.id
join users as u on u.id = uc.user_id
join (
select id as op_id, (
select count(distinct c.id)
from opportunities as op
join opportunity_certificates as oc on oc.opportunity_id = op.id
join certificates as c on c.id = oc.certificate_id and oc.is_required
join user_certificates as uc on uc.certificate_id = c.id
join users as u on u.id = uc.user_id
where uc.certificate_id = oc.certificate_id and oc.is_required and op.id = op_id
) as required from opportunities
) as required2 on required2.op_id = op_main.id
where uc.certificate_id = oc.certificate_id and oc.is_required and op_id = op_main.id
based on the table above the output would be:
opportunity main_user_id
1 161
2 466
3 222
3 123
3 875
3 348
I spent many hours trying to work it out. If someone is keen on helping me, I can send you the database. Thanks.
It is quite simple with windowed functions - MySQL 8 and above:
WITH cte AS (
SELECT *, COUNT(DISTINCT certificate_id) OVER(PARTITION BY user_id) AS cnt
FROM (
-- your query with joins
) sub
)
SELECT *
FROM cte
WHERE cnt = required_certificates;
DBFiddle Demo
It turns out that MySQL 8.0 doesn't support COUNT(DISTINCT ...) OVER so I used subquery with DISTINCT.
ER_NOT_SUPPORTED_YET: This version of MySQL doesn't yet support '(DISTINCT ..)'

SQL inner join with max function by groub

I have some problem from using the inner join with group by using max function.
my detail :
Table inventory
site_ID tank_number volume times-tramp ID
1 1 5000 06/08/2017 15:00 1
1 1 4900 06/08/2017 15:01 2
1 2 6000 06/08/2017 15:05 3
1 3 4000 06/08/2017 15:05 4
2 1 3000 06/08/2017 15:33 5
2 2 2000 06/08/2017 15:34 6
1 1 4800 06/08/2017 15:36 7
1 2 5800 06/08/2017 16:00 8
Table wp_users (wordpress)
ID Name
1 aaa
2 bbbb
Now, I using with wpdatatable plugin in wordpress so i want use the inner join and group with tank_number and using data update by times-strap
The result should be is :
When user "aaa" login then ID will is 1
the result that want to show.
site_ID tank_number volume times-tramp
1 1 4800 06/08/2017 15:36
1 2 5800 06/08/2017 16:00
1 3 4000 06/08/2017 15:05
But
I got the this result :
site_ID tank_number volume times-tramp
1 1 5000 06/08/2017 15:00
1 2 6000 06/08/2017 15:05
1 3 4000 06/08/2017 15:05
So can every one help to advise me so I have show my code the showing the error due to i can't join with 2 table by correct syntax sql.
this code can work without inner join
select site_id, tank_product, volume, timestramp from inventory as t1
inner join (
select tank_product as tank, max(timestramp) as time from inventory
where site_id=1 group by tank_product) as t2
on t1.tank_product = t2.tank and t1.timestramp = t2.time and t1.site_id=1
and Now I trying to using with inner join but not work now.
SELECT inventory.site_id,
inventory.tank_product,
inventory.volume,
inventory.timestramp,
wp_users.ID
FROM inventory as t1
INNER JOIN wp_users
(SELECT inventory.tank_product, max(inventory.timestramp) as time from inventory
WHERE inventory.site_id=wp_users.ID GROUP BY inventory.tank_product) as t2
ON t1.inventory.tank_product=t2.tank AND t1.inventory.timestramp=t2.time AND t1.inventory.site_id=wp_users.ID
Can advise me for correct way to use the inner join by group by max function.
So, the schema you present and the queries you provided don't line up (naming is all over the place). It would be very helpful if you provided a sql fiddle to help present your problem (at least in the future).
In any event, I think you were close:
select t2.site_id, t2.tank_product, t1.volume, t2.time
from (
select site_id, tank_product, max(timestramp) as time
from inventory
group by site_id,tank_product) t2
inner join inventory t1
on t2.site_id=t1.site_id and t1.tank_product=t2.tank_product and t2.time=t1.timestramp
inner join wp_users u
on u.id=t2.site_id
where u.id=1
order by t2.site_id,t2.tank_product asc
(Assuming you pass the wp_users.id into the query; I've hard-coded that with u.id=1.)
fiddle
Try to run this:
SELECT i1.site_ID, i1.tank_product, i1.volume, i.timestramp, iu.User_ID
FROM Inventory AS i1
INNER JOIN (
SELECT u.ID AS UserID, i.tank_product, MAX (i.timestramp) AS time
FROM Inventory AS i2
INNER JOIN wp_users AS u
ON i2.site_id = u.ID
GROUP BY u.ID, i.tank_product
) as iu
ON i1.tank_product = iu.tank_product
AND i1.timestramp = iu.time
AND i1.site_ID = iu.UserID;

MySQL join next lower value from other table

I've the two tables orders
id article amount
1 1 1
2 2 50
and prices
id article min_amount price
1 1 1 42.99
2 2 1 5.06
3 2 5 4.55
4 2 10 4.3
5 2 25 4.05
6 2 100 2.66
The prices tables contains IDs of articles and a minimum amount you would have to buy to get a bulk discount (which would change the price for the order). I would like to join prices into orders, so that the result looks like:
id article amount price
1 1 1 42.99
2 2 50 4.05
The order id 2 is above the minimum (25) to get the article for 4.05€, but still below 100 at which you would get a bigger discount, so the query would to have pick the next-lower value.
I've tried this query so far
SELECT
orders.id AS id,
orders.article,
orders.amount,
prices.price,
(orders.amount - prices.min_amount) AS discount_diff
FROM orders
LEFT JOIN prices ON (prices.article = orders.article) AND (prices.min_amount <= orders.amount)
which gives this result
id article amount price discount_diff
1 1 1 42.99 0
2 2 50 5.06 49
2 2 50 4.55 45
2 2 50 4.3 40
2 2 50 4.05 25
You can find this example on "js"fiddle: http://sqlfiddle.com/#!9/1b2bf/8
The query you need is this:
SELECT orders.id AS id,
orders.article,
orders.amount,
prices.price
FROM orders
INNER JOIN prices ON ( prices.article = orders.article
and prices.min_amount <= orders.amount)
INNER JOIN ( SELECT orders.article,
orders.amount,
min(prices.price) minprince
FROM orders
INNER JOIN prices ON (prices.article = orders.article
AND prices.min_amount <= orders.amount)
GROUP BY orders.article,
orders.amount) b
ON ( prices.article = b.article
AND orders.amount = b.amount
AND prices.price = b.minprince)
See it here: http://sqlfiddle.com/#!9/1b2bf/27

SQL select from tables

I've got tables:
Table1= USER_ID ITEM_ID
1 12
1 13
2 12
3 12
3 1
3 2
etc..
And second table:
Products = ITEM_ID PRICE
1 1.3
2 0.1
4 22
12 33
13 45
It is just example. How can I get ID's of clients who paid more than average order value?
I tried many times, but I always get errors.
You can do a JOIN between the tables and comparing the average price with specific user price paid like
select t1.user_id
from table1 t1
join products p on t1.item_id = p.item_id
group by t1.user_id
having p.price > avg(p.price);

having trouble writing a query that list all salesmen that did not sell to a particular customer

I was successful in writing the query that lists salesmen that did sell to a particular customer, but not those that have not. I suspect it is because the same salesmen that sold to the specific customer, also sold to other customers.
select a.name from salesperson a inner join orders b on
a.salesperson_id = b.salesperson_id where cust_id="4";
I was thinking that modifying the same query like this would do the trick:
.... a.salesperson_id <> b.salesperson_id where cust_id="4";
But the result lists all the salesmen. This is most likely due to the fact that the same salesmen that were returned in the original query, also sold to other customers
The 3 tables look like this:
Salesperson table
salesperson_ID, Name, Age, Salary
1 Abe 61 140000
2 Bob 34 44000
5 Chris 34 40000
7 Dan 41 52000
8 Ken 57 115000
11 Joe 38 38000
Customer table
cust_ID, Name, City Industry Type
4 faralon sacramento H
6 Apple cupertino S
7 Honda NY B
9 Kolb Oshkosh B
Orders table
Number, Order_date, cust_id, salesperson_id, Amount
10 8/2/1996 4 2 540
20 1/30/1999 4 8 1800
30 7/14/1995 9 1 460
40 1/29/1998 7 2 2400
50 2/3/1998 6 7 600
60 3/2/1998 6 7 720
70 5/6/1998 9 7 150
Any help would be greatly appreciated. ~Alpinehyker
You can do something like this:
select a.name from salesperson a
left join orders b on a.salesperson_id = b.salesperson_id and b.cust_id="4"
where b.Number is null
So, get all salepersons, left join to orders for customer 4, and return only rows where there is no such order.
I am assuming that Number is the primary key for Orders, or at least not null.
All salespeople who have NOT sold to customer_ID 4:
SELECT s.Name FROM Salesperson AS s
LEFT JOIN Orders AS o
ON s.salesperson_ID = o.salesperson_ID
WHERE o.customer_ID <> 4
GROUP BY o.salesperson_ID;
Perhaps this will work
SELECT
s.*
FROM `Salesperson` AS s
LEFT JOIN `Orders` AS o ON o.`salesperson_id` = s.`salesperson_ID`
WHERE
o.`cust_id` NOT IN (4)
GROUP BY s.`salesperson_ID`;
Answer to your 2nd question:
SELECT
COUNT(*) AS num_of_orders
,s.`Name`
FROM `Salesperson` AS s
LEFT JOIN `Orders` AS o ON o.`salesperson_id` = s.`salesperson_ID`
GROUP BY s.`salesperson_ID`
HAVING num_of_orders >= 2;
...and 3rd question. (assuming you have your highAchiever table ready)
INSERT INTO `highAchiever`
(`Name`,`Age`)
SELECT
`Name`
,`Age`
FROM `Salesperson`
WHERE
`Salary` >= 100000;