How to get column which is assigned under another column - mysql

I have 2 tables.
This is my GroupTable.
CREATE TABLE GroupTable(
ID INT,
GROUPNAME VARCHAR(50),
UnderGroupId INT
);
INSERT INTO GroupTable VALUES (1,'A',0);
INSERT INTO GroupTable VALUES (2,'B',1);
INSERT INTO GroupTable VALUES (3,'C',2);
INSERT INTO GroupTable VALUES (4,'D',3);
Below is the datatable where i'm passing groupId in data table for reference
CREATE TABLE Reference(
ID INT,
GROUPID VARCHAR(50),
GroupValue VARCHAR(50)
);
INSERT INTO Reference VALUES (1,3,'X');
INSERT INTO Reference VALUES (2,4,'Y');
INSERT INTO Reference VALUES (3,1,'Z');
and i want to show the result like this
| ID | GROUPID | GroupValue | GROUPNAME1 | GROUPNAME2 | GROUPNAME3 | GROUPNAME4 |
|----|---------|------------|------------|------------|------------|------------|
| 1 | 3 | X | A | B | C | |
| 2 | 4 | Y | A | B | C | D |
| 3 | 1 | Z | A | | | |

From your comment, you can try to OUTER JOIN by GROUPID > UnderGroupId condition because that condition is those two table relationship condition.
then
UnderGroupId = 0 mean the group1
UnderGroupId = 1 mean the group2
UnderGroupId = 2 mean the group3
UnderGroupId = 3 mean the group4
You can do condition aggregate function on UnderGroupId, to get the pivot result.
TestDLL
CREATE TABLE GroupTable(
ID INT,
GROUPNAME VARCHAR(50),
UnderGroupId INT
);
INSERT INTO GroupTable VALUES (1,'A',0);
INSERT INTO GroupTable VALUES (2,'B',1);
INSERT INTO GroupTable VALUES (3,'C',2);
INSERT INTO GroupTable VALUES (4,'D',3);
CREATE TABLE Reference(
ID INT,
GROUPID VARCHAR(50),
GroupValue VARCHAR(50)
);
INSERT INTO Reference VALUES (1,3,'X');
INSERT INTO Reference VALUES (2,4,'Y');
INSERT INTO Reference VALUES (3,1,'Z');
Query 1:
SELECT t1.ID,
t1.GROUPID,
t1.GroupValue,
coalesce(MAX(CASE WHEN UnderGroupId = 0 THEN tt.GROUPNAME end),'') GROUPNAME1,
coalesce(MAX(CASE WHEN UnderGroupId = 1 THEN tt.GROUPNAME end),'') GROUPNAME2,
coalesce(MAX(CASE WHEN UnderGroupId = 2 THEN tt.GROUPNAME end),'') GROUPNAME3,
coalesce(MAX(CASE WHEN UnderGroupId = 3 THEN tt.GROUPNAME end),'') GROUPNAME4
FROM Reference t1
LEFT JOIN GroupTable tt ON t1.GROUPID > tt.UnderGroupId
GROUP BY t1.ID,
t1.GROUPID,
t1.GroupValue
Results:
| ID | GROUPID | GroupValue | GROUPNAME1 | GROUPNAME2 | GROUPNAME3 | GROUPNAME4 |
|----|---------|------------|------------|------------|------------|------------|
| 1 | 3 | X | A | B | C | |
| 2 | 4 | Y | A | B | C | D |
| 3 | 1 | Z | A | | | |

Related

Deleting table entries based on criteria in another table

We want to be able to delete entries from a MySQL table, based on deletion criteria set in another table. Let me explain with an example.
I have two tables defined as follows:
CREATE TABLE base_tbl
(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
f1 VARCHAR(8),
f2 VARCHAR(8),
PRIMARY KEY (id)
);
CREATE TABLE del_criteria_tbl
(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
f3 VARCHAR(8),
f4 VARCHAR(8),
PRIMARY KEY (id)
);
base_tbl has the data and del_criteria_tbl has the criteria for deleting entries from base_tbl.
I populate the tables as follows:
INSERT INTO base_tbl(f1, f2) VALUES ('ABC', '123C57'),
('ABC', '532B49'), ('DEF', '397F45'),
('DEF', '684G65'), ('GHI', '793A86'),
('GHI', '541H32');
and
INSERT INTO del_criteria_tbl(f3, f4) VALUES ('ABC', '532B49'),
('ABC', '813E89'), ('DEF', '397F45'),
('GHI', '541H32');
Obviously:
mysql>SELECT * FROM base_tbl;
+----+------+--------+
| id | f1 | f2 |
+----+------+--------+
| 1 | ABC | 123C57 |
| 2 | ABC | 532B49 |
| 3 | DEF | 397F45 |
| 4 | DEF | 684G65 |
| 5 | GHI | 793A86 |
| 6 | GHI | 541H32 |
+----+------+--------+
mysql>SELECT * FROM del_criteria_tbl;
+----+------+--------+
| id | f3 | f4 |
+----+------+--------+
| 1 | ABC | 532B49 |
| 2 | ABC | 813E89 |
| 3 | DEF | 397F45 |
| 4 | GHI | 541H32 |
+----+------+--------+
I would like to define a succinct and efficient SQL operation that executes the following pseudo-SQL logic:
DELETE FROM base_tbl WHERE base_tbl.f1 = del_criteria_tbl.f3 AND base_tbl.f2 = del_criteria_tbl.f4
After the operation is executed, SELECT * FROM base_tbl should yield:
+----+------+--------+
| id | f1 | f2 |
+----+------+--------+
| 1 | ABC | 123C57 |
| 4 | DEF | 684G65 |
| 5 | GHI | 793A86 |
+----+------+--------+
A simple method is IN:
DELETE b FROM base_tbl b
WHERE (b.f1, b.f2) IN (SELECT dc.f3, dc.f4
FROM del_criteria_tbl dc
);
With indexes on (f1, f2), you might find a JOIN has better performance:
DELETE b
FROM base_tbl b JOIN
del_criteria_tbl dc
ON b.f1 = dc.f3 AND b.f2 = c.f4;
I would recommend exists:
delete b
from base_tbl b
where exists (
select 1
from del_criteria_tbl dc
where dc.f1 = b.f1 and dc.f2 = b.f2
)
This seems like the most natural way to phrase what you ask for. exists usually scales better than in over large datasets. For performance, you want an index on del_criteria_tbl(f1, f2).

Get result from joined tables

I have 2 tables:
Table 1:
| jobid | jobname |
| 1 | job a |
| 2 | job b |
Table 2:
| id | jobid | statusid | statusdate | desc |
| 1 | 1 | 100 | 2019.04.25 10:00:00 | first |
| 2 | 2 | 100 | 2019.04.25 11:00:00 | first |
| 3 | 2 | 100 | 2019.04.25 12:00:00 | second |
Jobs in table2 can have more then one same "statusid", but different "statusdate" and "desc"
I need to get jobs list with the last "statusid" = 100 like this :
| 1 | job a | 1 | 1 | 100 | 2019.04.25 10:00:00 | first |
| 2 | job b | 3 | 2 | 100 | 2019.04.25 12:00:00 | second |
SELECT * FROM table1
INNER JOIN table2 ON table1.id = table2.jobid
GROUP BY table1.id
This query return wrong result like:
| 1 | job a | 1 | 1 | | 100 | 2019.04.25 10:00:00 | first |
| 2 | job b | 3 | 2 | 2 | 100 | 2019.04.25 11:00:00 | first |
You should be able to accomplish that by doing something like this:
Table
drop table if exists table1;
create table table1 (jobid int, jobname char(10));
insert into table1 values (1, 'job a'), (2, 'job b');
drop table if exists table2;
create table table2 (
id int,
jobid int,
statusid int,
statusdate timestamp,
`desc` char(10)
);
insert into table2 values
(1,1,100,'2019.04.25 10:00:00','first')
,(2,2,100,'2019.04.25 11:00:00','first')
,(3,2,100,'2019.04.25 12:00:00','second');
Query
select
t1.*,
t2.*
from table1 t1
inner join (
select jobid, max(statusdate) as maxstatusdate
from table2
group by jobid
) tn on t1.jobid = tn.jobid
inner join table2 t2 on tn.jobid = t2.jobid and tn.maxstatusdate = t2.statusdate;
Results
jobid jobname id jobid statusid statusdate desc
1 job a 1 1 100 25.04.2019 10:00:00 first
2 job b 3 2 100 25.04.2019 12:00:00 second
Explanation
For each job ID, find the maximum status date
Join that to table1 to get information from table1. Common field is jobid
Join their result to table2 that has all the remaining information you want. Common fields are jobid and statusdate. Since we aliased max status date to a different name, make sure we are using the correct name in the join
Example: https://rextester.com/HRSWZ89705
DROP TABLE IF EXISTS table1;
CREATE TABLE table1
(jobid INT NOT NULL PRIMARY KEY
,jobname VARCHAR(12) UNIQUE
);
INSERT INTO table1 VALUES
(1,'job a'),
(2,'job b'),
(3,'job c');
DROP TABLE IF EXISTS table2;
CREATE TABLE table2
(id SERIAL PRIMARY KEY
,jobid INT NOT NULL
,statusid INT NOT NULL
,statusdate DATETIME NOT NULL
,description VARCHAR(12) NOT NULL
);
INSERT INTO table2 VALUES
(1,1,100,'2019-04-25 10:00:00','first'),
(2,2,100,'2019-04-25 11:00:00','first'),
(3,2,100,'2019-04-25 12:00:00','second');
SELECT a.*
, b.id x_id
, b.statusid
, b.statusdate
, b.description
FROM table1 a
LEFT
JOIN
( SELECT x.*
FROM table2 x
JOIN
( SELECT MAX(id) id
FROM table2
WHERE statusid = 100
GROUP
BY jobid
) y
ON y.id = x.id
) b
ON b.jobid = a.jobid
;
+-------+---------+------+----------+---------------------+-------------+
| jobid | jobname | x_id | statusid | statusdate | description |
+-------+---------+------+----------+---------------------+-------------+
| 1 | job a | 1 | 100 | 2019-04-25 10:00:00 | first |
| 2 | job b | 3 | 100 | 2019-04-25 12:00:00 | second |
| 3 | job c | NULL | NULL | NULL | NULL |
+-------+---------+------+----------+---------------------+-------------+
SELECT
t1.*,t2.* FROM
(SELECT
MAX(id) as id
FROM
table2
WHERE statusid = 100
GROUP BY jobid) AS f
JOIN table2 t2
ON t2.id = f.id
JOIN table1 t1
ON t2.jobid = t1.jobid
The sub query select finds the last id for a row with statusid 100, then it joins the actual table based on this id.
You can reorder this as you wish using the correct joins.

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)

Group by priority

I have this
+---------+--------+-------+
| article | name |status |
+---------+--------+-------+
| 0001 | A | enable|
| 0002 | A | temp |
| 0003 | B | enable|
| 0004 | C | enable|
+---------+--------+-------+
I want to select all from this table 'product' but I want to group by name and if there is a status temp I want to ignore the enable status and display only the product with the temp status
This result after query will be :
+---------+--------+-------+
| article | name |status |
+---------+--------+-------+
| 0002 | A | temp |
| 0003 | B | enable|
| 0004 | C | enable|
+---------+--------+-------+
Could you help me to build this query ?
If find at least one temp in group, show it. Else show enable
select article, name, if(sum(status='temp'), 'temp', 'enable')
from thetable
group by name
To get article corresponding to temp status, use such query
select * from table1
where status = 'temp'
union
select * from table1
where name not in (select distinct name from table1 where status = 'temp' )
Try this, hope help for you;)
SQL Fiddle
MySQL 5.6 Schema:
CREATE TABLE table1
(`article` int, `name` varchar(1), `status` varchar(6))
;
INSERT INTO table1
(`article`, `name`, `status`)
VALUES
(0001, 'A', 'enable'),
(0002, 'A', 'temp'),
(0003, 'B', 'enable'),
(0004, 'C', 'enable')
;
Query 1:
select t1.*
from table1 t1
inner join (
select count(distinct status) cnt, name, group_concat(status) as names from table1 group by name
) t2 on t1.name = t2.name
and (t2.cnt = 1 or (find_in_set('temp', names) > 0 and t1.status = 'temp'))
group by t1.name, t1.status
Results:
| article | name | status |
|---------|------|--------|
| 2 | A | temp |
| 3 | B | enable |
| 4 | C | enable |

How to join 3 table in mysql with rule?

First, I have 3 table.
Table 1 data:
tid | type_1 | address_1 | contact_1
----+--------+-----------+-----------+
1 | 4 | No.2123 | 01234567
4 | 4 | No.4567 | 00011234
Table 2 data:
tid | type_2 | address_2 | contact_2
----+--------+-----------+-----------+
2 | 3 | No.8888 | 7654321
Table 3 data:
tid | subject | desc
----+---------+-------------+
1 | Test 1 | Desc 1
2 | Test 2 | Desc 2
3 | Test 3 | Desc 3
4 | Test 4 | Desc 4
I would like to combine like this:
tid | subject | type_1 | type_2 | address_1 | address_2 | contact_1 | contact_2 | desc
----+---------+--------+--------+-----------+-----------+-----------+-----------+------
1 | Test 1 | 4 | | No.2123 | |01234567 | | Desc1
2 | Test 2 | | 3 | |No.8888 | |7654321 | Desc2
4 | Test 4 | 4 | | No.4567 | |00011234 | | Desc4
if table 1 got "tid" 1, then table 2 never got the same tid.
Ignore if tid no found in table 1 and table 2
Thanks!
My code before is:
$query = mysql_query("SELECT table1.*, table2.*, table3.subject, table3.desc, FROM table1 ON table1.tid = table3.tid LEFT JOIN table2 ON table2.tid = table3.tid LEFT JOIN table3 ON table1.tid AND table2.tid = table3.tid");
SELECT
table1.tid,
table3.subject,
table1.type_1,
NULL AS type_2,
table1.address_1,
NULL AS address_2,
table1.contact_1,
NULL AS contact_2,
table3.`desc`
FROM table1
INNER JOIN table3 ON table1.tid=table3.tid
UNION ALL
SELECT
table2.tid,
table3.subject,
NULL AS type_1,
table2.type_2,
NULL AS address_1,
table2.address_2,
NULL AS contact_1,
table2.contact_2,
table3.`desc`
FROM table2
INNER JOIN table3 ON table2.tid=table3.tid
DROP TABLE IF EXISTS table1;
CREATE TABLE table1
(tid INT NOT NULL
,type_1 INT NOT NULL
,address_1 VARCHAR(12) NOT NULL
,contact_1 VARCHAR(12) NOT NULL
);
INSERT INTO table1 VALUES
(1 ,4 ,'No.2123','01234567'),
(4 ,4 ,'No.4567','00011234');
DROP TABLE IF EXISTS table2;
CREATE TABLE table2
(tid INT NOT NULL
,type_2 INT NOT NULL
,address_2 VARCHAR(12) NOT NULL
,contact_2 VARCHAR(12) NOT NULL
);
INSERT INTO table2 VALUES
(2 ,3 ,'No.8888','7654321');
DROP TABLE IF EXISTS table3;
CREATE TABLE table3
(tid INT NOT NULL
,subject VARCHAR(12) NOT NULL
,description VARCHAR(12) NOT NULL
);
INSERT INTO table3 VALUES
(1 ,'Test 1','Desc 1'),
(2 ,'Test 2','Desc 2'),
(3 ,'Test 3','Desc 3'),
(4 ,'Test 4','Desc 4');
SELECT x.*
, y.subject
, y.description
FROM
( SELECT tid
, type_1
, NULL type_2
, address_1
, contact_1
, NULL address_2
, NULL contact_2
FROM table1
UNION
SELECT tid
, NULL
, type_2
, NULL
, NULL
, address_2
, contact_2
FROM table2
) x
JOIN table3 y
ON y.tid = x.tid;
+-----+--------+--------+-----------+-----------+-----------+-----------+---------+-------------+
| tid | type_1 | type_2 | address_1 | contact_1 | address_2 | contact_2 | subject | description |
+-----+--------+--------+-----------+-----------+-----------+-----------+---------+-------------+
| 1 | 4 | NULL | No.2123 | 01234567 | NULL | NULL | Test 1 | Desc 1 |
| 2 | NULL | 3 | NULL | NULL | No.8888 | 7654321 | Test 2 | Desc 2 |
| 4 | 4 | NULL | No.4567 | 00011234 | NULL | NULL | Test 4 | Desc 4 |
+-----+--------+--------+-----------+-----------+-----------+-----------+---------+-------------+
3 rows in set (0.00 sec)
The JOIN clause you have written is not in correct format. You should use it like this:
`table1 JOIN table2 ON` your conditions to join the table.
You can get more about JOIN from here.
So you can try this:
SELECT table3.tid AS tid,
t3.subject AS subject,
t1.type_1 AS type_1,
t2.type_2 AS type_2,
t1.address_1 AS address_1,
t2.address_2 AS address_2,
t1.contact_1 AS contact_1,
t2.contact_2 AS contact_2,
t3.desc AS description
FROM table3 t3
INNER JOIN table1 t1 ON t3.tid = t1.tid
INNER JOIN table2 t2 ON t3.tid = t2.tid