SQL query to select distinct row with minimum value from two table - mysql

I want a sql query to get the row of products with a minimum price and get all of other fields of two table.
Consider this table:
T1: T2:
id Title id pcount price t1_id(foreign key)
1 x 1 3 3000 2
2 y 2 8 2500 2
3 z 3 4 1200 1
4 6 1000 1
5 9 4000 3
How can I select the below columns that have the minimum value in the price column, grouped by Title and get below fields? Like this:
id Title pcount price t1_id
1 y 8 2500 2
2 x 6 1000 1
3 z 9 4000 3

For Sql Server you can use OUTER APPLY:
select * from t1
outer apply(select top 1 * from t2 where t1_id = t1.id order by price) oa

Try like this,
SELECT t1.*,
t3.*
FROM T1 t1
CROSS apply (SELECT Min(price) AS price
FROM T2
WHERE t1_id = t1.tableid)t2
LEFT OUTER JOIN t2 t3
ON t3.t1_id = t1.tableid
AND t3.price = t2.price

select *
from t1
left join
(select pcount, price, t2.t1_id
from t2
join
(select t1_id, min(price) pmin
from t2
group by t1_id
) tt
where t2.t1_id = tt.t1_id and price = pmin
) tt1
on t1.id = tt1.t1_id
result
id Title pcount price t1_id
1 x 6 1000 1
2 y 8 2500 2
3 z 9 4000 3

Also check this :
declare #t1 table(id int , title varchar(50))
declare #t2 table(id int , pcount int, price int, t1_id int)
insert into #t1 values (1, 'x' ), (2,'y'), (3,'z')
insert into #t2 values (1, 3, 3000, 2 ), (2, 8, 2500, 2 ),(3, 4, 1200, 1 ),(4, 6, 1000, 1),(5, 9, 4000, 3)
;with cte
as(
select * from (select * , ROW_NUMBER() OVER (PARTITION BY t1_id ORDER BY t1_id asc, price asc ) AS sequence_id from #t2 ) a where sequence_id = 1
)
select t1.*, cte.pcount ,cte.price from #t1 t1 join cte on t1.id = cte.t1_id
--or understand more
;with cte as
(
select t1_id, min(price) price
from #t2 group by t1_id
)
, cte1 as
(
select t1.*,t2.pcount, cte.* from #t1 t1
left outer join #t2 t2 on t1.id = t2.t1_id
left outer join cte cte on t1.id = cte.t1_id and (t2.t1_id =cte.t1_id and t2.price = cte.price)
)
select * from cte1 where t1_id is not null

Related

Group SQL data and split into columns

I have a table with the following columns, where the timestamp column indicates the date the user viewed a product, and the purchase column if the view generated a purchase:
id
userId
productId
timestamp
purchase
1
2
4
2022-01-07
0
2
2
4
2022-01-10
1
3
2
4
2022-01-12
0
4
2
4
2022-01-16
1
How to group the data by userId and productId in order to return as follows:
id
userId
productId
firstView
lastView
firstPurchase
1
2
4
2022-01-07
2022-01-16
2022-01-10
For the firstView and listView columns I know I should use Min() and Max(), but the firstPurchase column I can't display. I tried using CASE when column purchase = 1 but it didn't work.
You need to use MIN(CASE WHEN purchase = 1 THEN "timestamp" ELSE NULL END), like this:
create table your_table (id int, userId int, productId int, "timestamp" date, purchase int)
insert into your_table (id, userId, productId, "timestamp", purchase)
values
(1,2,4,'2022-01-07 00:00:00',0),
(2,2,4,'2022-01-10 00:00:00',1),
(3,2,4,'2022-01-12 00:00:00',0),
(4,2,4,'2022-01-16 00:00:00',1);
SELECT
userId,
productId,
MIN(timestamp) AS firstView,
MAX(timestamp) AS lastView,
MIN(CASE WHEN purchase = 1 THEN "timestamp" ELSE NULL END) AS firstPurchase
FROM your_table
GROUP BY
userId,
productId;
p.s. please don't call a column "timestamp" :)
Try this:
SELECT t1.id, t1.userId, t1.productId, t1.timestamp,
(SELECT t3.timestamp
FROM yourtable t3
WHERE t3.userId = t1.userId
AND t3.productId = t1.productId
AND NOT EXISTS
(SELECT 1
FROM yourtable t4
WHERE t4.userId = t3.userId
AND t4.productId = t3.productId
AND t4.timestamp > t3.timestamp
)
) as lastView,
(SELECT t3.timestamp
FROM yourtable t3
WHERE t3.userId = t1.userId
AND t3.productId = t1.productId
AND t3.purchase = 1
AND NOT EXISTS
(SELECT 1
FROM yourtable t4
WHERE t4.userId = t3.userId
AND t4.productId = t3.productId
AND t4.timestamp < t3.timestamp
AND t4.purchase = 1
)
) as firstPurchase
FROM yourtable t1
WHERE NOT EXISTS
(SELECT 1 FROM yourtable t2
WHERE t1.userId = t2.userId
AND t1.productId = t2.productId
AND t2.timestamp < t1.timestamp)
See Sql Fiddle

Mysql - reorder / reset position key

I have a MySQL table with position key (65,000 records). I deleted, updated some rows in the middle of the table. Now I have, for example, something like this in the position 1 - 6 - 2 - 9
id
category
position
1
1
1
2
1
6
3
2
2
4
2
9
I want to reset / reorder the position key
id
category
position
1
1
1
2
1
2
3
2
1
4
2
2
How can I reset position where category = 1
and where category = 2?
Try this:
UPDATE source_table
JOIN ( SELECT id, ROW_NUMBER() OVER (PARTITION BY category ORDER BY position) position
FROM source_table ) subquery USING (id)
SET source_table.position = subquery.position
mysql> SHOW VARIABLES LIKE "%version%"; 5.7.24 – sagittarius
UPDATE source_table
JOIN ( SELECT t1.id, COUNT(t2.id) position
FROM source_table t1
JOIN source_table t2 ON t1.category = t2.category
AND t1.position >= t2.position
GROUP BY t1.id ) subquery USING (id)
SET source_table.position = subquery.position;
fiddle
if position is duplicated everything crashes – sagittarius
UPDATE source_table
JOIN ( SELECT t1.id, COUNT(t2.id) position
FROM source_table t1
JOIN source_table t2 ON t1.category = t2.category
AND ( t1.position > t2.position
OR ( t1.position = t2.position
AND t1.id >= t2.id ))
GROUP BY t1.id ) subquery USING (id)
SET source_table.position = subquery.position;
fiddle
UPDATE source_table t1
INNER JOIN
(
SELECT id,category,position, ROW_NUMBER() OVER (PARTITION BY category
ORDER BY position) position2
FROM source_table
) t2
ON t2.id = t1.id
SET
t1.position = t2.position2
I think this code is easy to understand and apply.

Get all data from table who has minimum price

I have following data in my table t1
unique_id myid price1 price2 price3 price4
1 100 20 30 40 50
2 200 12 24 48 90
3 100 15 20 30 25
4 300 100 200 300 400
5 400 10 10 20 40
6 100 5 6 7 8
7 200 1 2 3 4
Now i want data of particular myid and whose price3 is minimum
Expected output :
unique_id myid price1 price2 price3 price4
1 100 5 6 7 8
2 200 1 2 3 4
4 300 100 200 300 400
I have tried following query :
select t1.*,t2.txn_amount from table1 t1
left join table1 t2 on t2.ummyid = t1.myid
where t1.myid IN (100,200,300)
GROUP by t1.myid HAVING min(price3)
But it is not working as expected.
If your db version not allow over partition` you could use a join with the subquery for min values
select * from table1 t1
inner join (
select myid, min(price3) min_price
from table1
group by myid
) t on t.myid = t1.myid
and t.min_price = t1.price
And for you case
select t1.*
, t2.txn_amount
from table1 t1
inner join (
select myid, min(price3) min_price
from table1
group by myid
) t on t.myid = t1.myid
and t.min_price = t1.price
left join table1 t2 on t2.ummyid = t1.myid
where t1.myid IN (100,200,300)
GROUP by t1.myid
If you are using MySQL 8.0 then following solution should work using window function row_number. Here is the demo.
select
unique_id,
myid,
price1,
price2,
price3,
price4
from
(
select
unique_id,
myid,
price1,
price2,
price3,
price4,
row_number() over (partition by myid order by price3) as rn
from myTable
) subq
where rn = 1
You have to use analytic functions, please use below query
select unique_id, myid, price1, price2, price3, price4 from
(slect unique_id, myid, price1, price2, price3, price4,
row_number() over(partition by myid order by price3) as rnk from table) qry
where rnk = 1;
I think that this solution should work:
Select distinct myid,
min(price3)
from t1 group by myid

Select the last price according to the date using GROUP BY

I'm trying to do a request with a group BY.
Here is an exemple of my table ticket :
id DtSell Price Qt
1 01-01-2017 3.00 1
1 02-01-2017 2.00 3
2 01-01-2017 5.00 5
2 02-01-2017 8.00 2
And my request :
SELECT id, Price, sum(Qt) FROM ticket
GROUP BY id;
but unfortunately, the price returned is not necessarily the right one; I would like to have the last price according to DtSell like that :
id Price sum(Qt)
1 2.00 4
2 8.00 7
But i didn't find how to do it.
Can you help me ?
Thank you in advance!!
You might need a sub query,try below:
SELECT
t1.id,
(SELECT t2.price FROM ticket t2 WHERE t2.id=t1.id
ORDER BY t2.DtSell DESC LIMIT 1 ) AS price,
SUM(t1.Qt)
FROM ticket t1 GROUP BY t1.id;
You can do this with a group_concat()/substring_index() trick:
SELECT id, Price, SUM(Qt)
SUBSTRING_INDEX(GROUP_CONCAT(price ORDER BY dtsell DESC), ',' 1) as last_price
FROM ticket
GROUP BY id;
Two notes:
This is subject to internal limits on the length of the intermediate string used for GROUP_CONAT() (a limit that can easily be changed).
It changes the type of price to a string.
Try this query.
SELECT id, Price, sum(Qt) FROM ticket
GROUP BY id,Price
Your Output;
id Price sum(Qt)
1 3.00 4
2 8.00 7
You can select all rows from ticket grouped by id ( to sum quantity), then join to the rows which have the max dtsell for each id group( to select the price).
http://sqlfiddle.com/#!9/574cb9/8
SELECT t.id
, t3.price
, SUM(t.Qt)
FROM ticket t
JOIN ( SELECT t1.id
, t1.price
FROM ticket t1
JOIN ( SELECT id
, MAX(dtsell) dtsell
FROM ticket
GROUP BY id ) t2
ON t1.id = t2.id
AND t1.dtsell = t2.dtsell ) t3
ON t3.id = t.id
GROUP BY t.id;
You can do it like this:
declare #t table (id int, dtsell date, price numeric(18,2),qt int)
insert into #t
values
(1 ,'01-01-2017', 3.00 , 1),
(1 ,'02-01-2017', 2.00 , 3),
(2 ,'01-01-2017', 5.00 , 5),
(2 ,'02-01-2017', 8.00 , 2)
select x.id,price,z.Qt from (
select id,price,dtsell,row_number() over(partition by id order by dtsell desc ) as rn from #t
)x
inner join (select SUM(qt) as Qt,ID from #t group by id ) z on x.id = z.id
where rn = 1

SQL: Selecting a minimum value per unique group and changing values

I have a table that looks like this:
ID Date Category
x 1995 A
x 1996 B
z 1995 B
z 1996 A
y 1995 B
y 1996 B
What I want to do is to set the Category to whatever the value is for the minimum date per ID. So that the final result would look like:
ID Date Category
x 1995 A
x 1996 A
z 1995 B
z 1996 B
y 1995 B
y 1996 B
Does anyone know how to do this in SQL? Thanks!
You can use a subquery:
select
id,
date,
(
select category
from mytable x
where x.id = m.id
and not exists
(
select *
from mytable older
where older.id = x.id
and older.date < x.date
)
) as oldest_category
from mytable m;
This should do it although there might be a smarter way:
select table1.id, table1.date, t3.category
from table1
join (
select t1.id, t1.category
from table1 t1
join (
select id, min(date) as min_date
from table1
group by id
) t2 on t1.id = t2.id and t1.date = t2.min_date
) t3 on table1.id = t3.id
In the query your source table is named table1. The logic is that the inner derived table limits the outer to the min(date)
Sample SQL Fiddle
Try this
declare #t table (id char(1), date int, category char(1))
insert into #t
select 'x', 1995, 'A' union all
select 'x', 1996 , 'B' union all
select 'z', 1995 , 'B' union all
select 'z', 1996 , 'A' union all
select 'y', 1995 , 'B' union all
select 'y', 1996 , 'B'
select t1.Id,t1.Date,t2.category from #t as t1 left join
(
select t1.Id,t1.Date,t1.category from #t as t1 inner join
(
select ID, min(Date) as Date from #t group by ID
) as t2 on t1.Id=t2.Id and t1.Date=t2.Date
) as t2 on t1.Id=t2.Id