Select max values from double joined table - mysql

In DB i have three tables like:
+-----------------+--------+
| ident (PrimKey) | ident2 |
+-----------------+--------+
| 123 | 333 |
| 321 | 334 |
| 213 | 335 |
| 1234 | 336 |
+-----------------+--------+
+---------+----------+-------+-------+
| PrimKey | group_id | value | ident |
+---------+----------+-------+-------+
| 1 | 1 | 10 | 213 |
| 2 | 1 | 5 | 321 |
| 3 | 1 | 15 | 1234 |
| 4 | 1 | 10 | 1234 |
| 5 | 2 | 7 | 213 |
| 6 | 2 | 15 | 321 |
+---------+----------+-------+-------+
+---------+----------+----------+
| PrimKey | ident2_1 | ident2_2 |
+---------+----------+----------+
| 1 | 333 | 334 |
| 2 | 333 | 335 |
| 3 | 333 | 336 |
+---------+----------+----------+
The third table is connection between two rows from first one. And Second Contains data from different group of this rows.
I have to find max values from second table grouped by group_id for specific user connected rows from third table. In example 333.
The correct answer should be:
+----------+-------+-------+
| group_id | value | ident |
+----------+-------+-------+
| 1 | 15 | 1234 |
| 2 | 15 | 321 |
+----------+-------+-------+
But for now i have all rows sorted:
+----+----------+-------+-------+
| | group_id | value | ident |
+----+----------+-------+-------+
| 1 | 1 | 15 | 1234 |
| 2 | 1 | 10 | 213 |
| 3 | 1 | 5 | 321 |
| 4 | 2 | 15 | 321 |
| 5 | 2 | 10 | 1234 |
| 6 | 2 | 7 | 213 |
+----+----------+-------+-------+
Or correct rows with incorrect ident's
+----+----------+-------+-------+
| | group_id | value | ident |
+----+----------+-------+-------+
| 1 | 1 | 15 | 213 |
| 2 | 2 | 15 | 1234 |
+----+----------+-------+-------+
The sql is :
DROP TABLE first;
DROP TABLE second;
DROP TABLE third;
CREATE TABLE first(group_id integer, value integer, ident integer);
CREATE TABLE second(ident integer, ident2 integer);
CREATE TABLE third(ident_1 integer, ident_2 integer);
INSERT INTO first VALUES(1, 10, 213);
INSERT INTO first VALUES(1, 5, 321);
INSERT INTO first VALUES(1, 15, 1234);
INSERT INTO first VALUES(2, 10, 1234);
INSERT INTO first VALUES(2, 7, 213);
INSERT INTO first VALUES(2, 15, 321);
INSERT INTO second VALUES(123, 333);
INSERT INTO second VALUES(321, 334);
INSERT INTO second VALUES(213, 335);
INSERT INTO second VALUES(1234, 336);
INSERT INTO third VALUES (333, 334);
INSERT INTO third VALUES (333, 335);
INSERT INTO third VALUES (333, 336);
SELECT f.group_id, max(f.value) as value, f.ident
FROM first as f
INNER JOIN second AS s ON f.ident = s.ident
INNER JOIN third AS t ON t.ident_2 = s.ident2
WHERE t.ident_1 = '333'
GROUP BY f.group_id
ORDER BY f.group_id ASC, f.value DESC;
SELECT f.group_id, f.value as value, f.ident
FROM first as f
INNER JOIN second AS s ON f.ident = s.ident
INNER JOIN third AS t ON t.ident_2 = s.ident2
WHERE t.ident_1 = '333'
ORDER BY f.group_id ASC, f.value DESC;
Tested on: https://rextester.com/l/mysql_online_compiler
Greetings
EDIT:
The third table is something like connection between friends with are rows in second table. And the first table is contain scores for different tasks with are identified by group_id. I need the best friends scores for different tasks. So list of friends i have from third table. And scores i have from first one. Connection between this tables is second one.
EDIT2:
In First table as Primary Key is ident(PrimKey).
The second and third as primary key have just another column.
In Second column ident column is index connected to ident (PrimKey) from first table.
In Third table columns ident2_1 and ident2_2 are indexes connected to indet2 from first table.

I came up with this SQL:
SELECT f.group_id, f.value as value, f.ident
FROM first as f
INNER JOIN second AS s
ON f.ident = s.ident
INNER JOIN third AS t
ON t.ident_2 = s.ident2
WHERE t.ident_1 = '333'
and f.value IN ( SELECT MAX(f1.value)
FROM first as f1
WHERE f1.group_id = f.group_id )
ORDER BY f.group_id ASC, f.value DESC;

There is surely a more elegant solution, but this will give the result you asked for.
select m.*
from(
select f.group_id, f.value value, f.ident
from first f,
second s,
third t
where f.ident = s.ident
and t.ident_2 = s.ident2
and t.ident_1 = '333'
ORDER BY f.group_id ASC, f.value DESC ) m,
(
select max(f.value) value
from first f,
second s,
third t
where f.ident = s.ident
and t.ident_2 = s.ident2
and t.ident_1 = '333' ) n
where m.value = n.value
here is a second (also clunky) technique that delivers the desired results:
select f.group_id, f.value value, f.ident
from first f,
second s,
third t
where f.ident = s.ident
and t.ident_2 = s.ident2
and t.ident_1 = '333'
and value = ( select max(f.value) value
from first f,
second s,
third t
where f.ident = s.ident
and t.ident_2 = s.ident2
and t.ident_1 = '333' )
ORDER BY f.group_id ASC, f.value DESC

Related

selecting only newest row with specific value

Table:
person | borrow_date | is_borrowed | SN | date | id
1 | 2019-01-10...| 1 | 20 |2019-01-10...| 6
3 | 2019-01-09...| 3 | 10 |2019-01-09...| 5
1 | 2019-01-08...| 1 | 10 |2019-01-08...| 4
2 | 2019-01-08...| 1 | 10 |2019-01-08...| 3
1 | NULL | 2 | 20 |2019-01-07...| 2
1 | NULL | 2 | 10 |2019-01-07...| 1
My wanted output is to select newest rows where "is_borrowed" equals 1 and grouped by SN, so that when the query is executed with person=2 or person=3 then it would retrieve empty set. Whereas for person=1 it would give back two rows.
Wanted output (where person=1):
person | borrow_date | is_borrowed | SN | date |id
1 | 2019-01-10...| 1 | 20 | 2019-01-10...|6
1 | 2019-01-08...| 1 | 10 | 2019-01-08...|4
Wanted output (where person=2):
EMPTY SET
Wanted output (where person=3):
EMPTY SET
This is my current query and it sadly doesn't work.
SELECT a.SN, a.is_borrowed,a.max(date) as date, a.person
FROM table a
INNER JOIN (SELECT SN, MAX(date) as date, osoba from table where person like
"2" group by SN) as b
ON a.SN=b.SN and a.date=b.date
WHERE a.person like "2" and a.is_borrowed=1
If I correctly understood you from the question and the comment you made under it, here's one way to do it without specifying the person:
select *
from TableName as p
inner join (select max(borrow_date) as borrow_date,
SN
FROM TableName
where is_borrowed = 1
group by SN) as p2
on p.borrow_date = p2.borrow_date and p.SN = p2.SN
This should give you the result you're looking for. Here's a demo.
Note that I had to change the borrowed_date values in the table since yours contain hours and minutes while I didn't add those.
You can always specify it for each person by adding a where clause after the join.
select p.person,
p.borrow_date,
p.is_borrowed,
p.SN,
p.date,
p.id
from TableName as p
inner join (select max(borrow_date) as borrow_date,
SN
FROM TableName
where is_borrowed = 1
group by SN) as p2
on p.borrow_date = p2.borrow_date and p.SN = p2.SN
where p.person = '1'
Output:
person | borrow_date | is_borrowed | SN | date | id
1 | 2019-01-10 | 1 | 20 | 2019-01-10 | 6
1 | 2019-01-08 | 1 | 10 | 2019-01-08 | 4
While where p.person = '2' and where p.person = '3' will return empty sets.

MySQL: One To Many Combinations

Below is the table data (Order_audit)
+------------+-----------------+
| OrderID | shipping_type |
+------------+-----------------+
| W1 | 0 |
| W1 | 2 |
| W2 | 2 |
| W3 | 2 |
| W3 | 2 |
| W3 | 1 |
| W4 | 0 |
| W5 | 1 |
| W5 | 2 |
+------------+-----------------+
I want sql to extract orderID having shipping_type with combinations of (0 or 1) and 2. In this example W1,W3,W5 are orders which fall in this criteria.
Assuming Table Name is order_audit.
Kindly help me on this.
We can try aggregating by OrderID and then asserting the following two conditions on each order group:
There are two (and only two) distinct shipping_type values present
One of those shipping_type values is 2
If both of the above conditions are true, it would imply that the order had either (0, 2) or (1, 2) as shipping combinations.
SELECT OrderID
FROM yourTable
WHERE shipping_type IN (0, 1, 2)
GROUP BY OrderID
HAVING
COUNT(DISTINCT shipping_type) = 2 AND
MAX(CASE WHEN shipping_type = 2 THEN 1 ELSE 0 END) = 1;
Demo
One way to do it would be with this query which looks for all orders which have a shipping_type of 0 or 1 and have a matching entry with a shipping_type of 2.
SELECT OrderID
FROM order_audit a1
WHERE shipping_type IN(0,1) AND
EXISTS (SELECT *
FROM order_audit a2
WHERE a2.OrderID = a1.OrderID AND shipping_type = 2)
Demo

Multiple times values are coming in mysql

I have two tables
tbl1 and tbl2
tbl1 table contains 5 columns name id(pk), email , address ,pid(INDEX),status(ENUM Y,N)
tbl2 table contains 3 columns id(pk) ,pid(INDEX),domain
When i am running this query
SELECT *
FROM tbl1 as l
LEFT JOIN tbl2 as m on l.pid=m.pid
WHERE l.status='Y';
It is giving multiple records . Please note we are making join in pid both pid are not primary key. Please help to get only unique values from both table.
enter image description here
You seem to want to join on the basis of relative position in the tables.A way to do this is row_number simulation using variables.
drop table if exists t1,t2;
create table t1(id int, email varchar(5),address varchar(10),pid int,status varchar(1));
create table t2(id int, pid int, domain varchar(5));
insert into t1 values (1,'aa#aa', 'aaaaa',428,'Y'), (2,'bb#bb', 'bbbbb',428,'n'),(3,'cc#cc', 'ccccc',428,'Y') ;
insert into t2 values (1,428,'mmm'),(2,428,'zzz');
select t1.*,t2.*
from
(
select t1.*,
if(t1.pid <> #pid1, #bn1:=#bn1+1,#bn1:=#bn1) BlockNo1,
if(t1.id <> #id1, #rn1:=#rn1+1, #rn1:=1) rowno1,
#pid1:=t1.pid pid1,
#id1:=t1.id p1
from t1
cross join (select #bn1:=0,#rn1:=0, #pid1:=0 ,#id1:=0) r
where status = 'y'
order by t1.pid,t1.id
) t1
join
(
select t2.id t2id,t2.pid t2pid, t2.domain t2domain,
if(t2.pid <> #pid2, #bn2:=#bn2+1,#bn2:=#bn2) BlockNo2,
if(t2.id <> #id2, #rn2:=#rn2+1, #rn2:=1) rowno2,
#pid2:=t2.pid pid2,
#id2:=t2.id p2
from t2
cross join (select #bn2:=0,#rn2:=0, #pid2:=0 ,#id2:=0) r
order by t2.pid,t2.id
) t2 on (t1.blockno1 = t2.blockno2) and (t1.rowno1 = t2.rowno2)
+------+-------+---------+------+--------+----------+--------+------+------+------+-------+----------+----------+--------+------+------+
| id | email | address | pid | status | BlockNo1 | rowno1 | pid1 | p1 | t2id | t2pid | t2domain | BlockNo2 | rowno2 | pid2 | p2 |
+------+-------+---------+------+--------+----------+--------+------+------+------+-------+----------+----------+--------+------+------+
| 1 | aa#aa | aaaaa | 428 | Y | 1 | 1 | 428 | 1 | 1 | 428 | mmm | 1 | 1 | 428 | 1 |
| 3 | cc#cc | ccccc | 428 | Y | 1 | 2 | 428 | 3 | 2 | 428 | zzz | 1 | 2 | 428 | 2 |
+------+-------+---------+------+--------+----------+--------+------+------+------+-------+----------+----------+--------+------+------+
2 rows in set (0.04 sec)

Complex SQL query with group by and having in condition

Suppose I have the table test below:
------------------------------
id | active| record
------------------------------
3 | O | 2015-10-16
3 | O | 2015-10-15
3 | N | 2015-10-14
4 | N | 2015-10-15
4 | O | 2015-10-14
I want to do an update on the table on the lines with:
- An id having the column active = 'O' more than once.
- Among theses lines having active = 'O' more than once, the update shall change the value of active to 'N', except for the one with max(record), which will stay with active = 'O'.
In my example, the id having the column active = 'O' more than once is id = 3.
id |active | record
------------------------------
3 | O | 2015-10-16
3 | O | 2015-10-15
3 | N | 2015-10-14
I want to have this result:
id |active | record
------------------------------
3 | O | 2015-10-16
3 | N | 2015-10-15
3 | N | 2015-10-14
I tried this query, but there is an error:
update test as t1,
(select id
from test
where active = 'O'
group by id
having count(*) > 1) as t2
set t1.actif = 'N'
where t1.record != max(t2.record);
Thanks in advance!
Given this sample data:
CREATE TABLE t
(`id` int, `active` varchar(1), `record` date)
;
INSERT INTO t
(`id`, `active`, `record`)
VALUES
(3, 'O', '2015-10-16'),
(3, 'O', '2015-10-15'),
(3, 'N', '2015-10-14'),
(4, 'N', '2015-10-15'),
(4, 'O', '2015-10-14')
;
This query
UPDATE
t
JOIN (
SELECT
id, MAX(record) AS max_record
FROM
t
WHERE active = 'O'
GROUP BY id
HAVING COUNT(*) > 1
) sq ON t.id = sq.id
SET t.active = IF(t.record = sq.max_record, 'O', 'N');
produces this result:
+------+--------+------------+
| id | active | record |
+------+--------+------------+
| 3 | O | 2015-10-16 |
| 3 | N | 2015-10-15 |
| 3 | N | 2015-10-14 |
| 4 | N | 2015-10-15 |
| 4 | O | 2015-10-14 |
+------+--------+------------+
Can you try with something like this
select ID,
count(*) Counted,
max(record) record
into #TempTable from Table
where Active = 'O'
group by ID
Update tab
set tab.Active = 'N'
from Table tab
join #tempTable temp on tab.ID = temp.ID
where temp.Counted > 1 and
tab.record != temp.record
drop table #tempTable
Basically, you just counting Os while grabbing ID and max record into temp table and after that you doing the update, also this code might need some changes as i just took a glance to point you toward direction i would do it

how to join two tables using group by order by and limit

I have two tables
tblXYZ
patId | Name | DOB
---------------------------
1 | xyz | 10-05-1986
2 | abc | 12-06-01978
3 | lmn | 12-04-1975
tblABC
apptId | patId | status | otherinfo
-------------------------------------
1 | 1 | single | jmdfh
2 | 1 | sds | dfdf
3 | 2 | fdf | sdwed
4 | 2 | fdf | sdwed
I want join these two table to get result as:
result
patId | apptId | Name | DOB
--------------------------------
1 | 2 | single | jmdfh
2 | 4 | sds | dfdf
3 | null | fdf | sdwed
apptId should be the last entered value from tblABC
try something like that
select patId, apptId, Name, DOB
join -- or left join if you want patId that doesn't have match in the second table
(
select patId AS patIdBis, max(apptId) AS apptId
from tblABC group by patId
)
on patId = patIdBis
order by patId;
If by "last entered" you mean largest apptId, then the following query will do what you want.
SELECT tblXYZ.patId, tblABC.apptId, tblXYZ.name, tblXYZ.DOB
FROM tblXYZ
LEFT JOIN
(
(SELECT patId, MAX(apptId) mx FROM tblABC GROUP BY patId) maxes
INNER JOIN tblABC
ON maxes.patId = tblABC.patId AND maxes.mx = tblABC.apptId
) ON tblXYZ.patId = tblABC.patId;
UPDATE: Valentin Clement's query is shorter and is better if you only need the apptId from the tblABC. If you need any other data from the tblABC, then you need to use the query from my answer.
Use this query to get your result
SELECT x.patid, a.apptid, x.name, x.dob
FROM tblxyz x INNER JOIN tblabc a ON
x.patid=a.patid
patid apptid name DOB
1 1 xyz 1986-10-05 00:00:00.000
1 2 xyz 1986-10-05 00:00:00.000
2 3 abc 1978-12-06 00:00:00.000
2 4 abc 1978-12-06 00:00:00.000