Multiple times values are coming in mysql - 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)

Related

How to use temporary table in the from clause in mysql?

I am trying to write a query to get the designation which has got the highest and second lowest amount (salary + variables) for the whole year of 2019 along with the corresponding amount values.
Employees Table:
| Emp_id | first_name | Last_name | Salary | Joining_date | Department|
|:------ |:----------:|:---------:|:------:|:-----------------:|:---------:|
| 001 | Manish | Agarwal | 700000 |2019-04-20 09:00:00| HR |
| 002 | Niranjan | Bose | 20000 |2019-02-11 09:00:00| DA |
| 003 | Vivek | Singh | 100000 |2019-01-20 09:00:00| DA |
| 004 | Asutosh | Kapoor | 700000 |2019-03-20 09:00:00| HR |
| 005 | Vihaan | Banerjee | 300000 |2019-06-11 09:00:00| DA |
| 006 | Atul | Diwedi | 400000 |2019-05-11 09:00:00| Account |
| 007 | Sathyendra | Tripathi | 95000 |2019-03-20 09:00:00| Account |
| 008 | Prithika | Bhatt | 95000 |2019-03-20 09:00:00| DA |
Variables table:
| Emp_Ref_ID | Variables_Date | Variables_amount|
|:---------- |:------------------:|:---------------:|
| 1 |2019-02-20 00:00:00 | 15000 |
| 2 |2019-06-11 00:00:00 | 30000 |
| 3 |2019-02-20 00:00:00 | 42000 |
| 4 |2019-02-20 00:00:00 | 14500 |
| 5 |2019-06-11 00:00:00 | 23500 |
Designation table:
| Emp_Ref_ID | Emp_title | Affected_from |
|:---------- |:--------------:|:------------------:|
| 1 | Asst.Manager |2019-02-20 00:00:00 |
| 2 | Senior Analyst |2019-01-11 00:00:00 |
| 8 | Senior Analyst |2019-04-06 00:00:00 |
| 5 | Manager |2019-10-06 00:00:00 |
| 4 | Asst.Manager |2019-12-06 00:00:00 |
| 7 | Team Lead |2019-06-06 00:00:00 |
| 6 | Team Lead |2019-09-06 00:00:00 |
| 3 | Senior Analyst |2019-09-06 00:00:00 |
I tried the below query by creating a table called t1 and then fetching values from that
select emp_title , emp_ref_id from
(select d.emp_ref_id , d.emp_title, e.salary+v.variables_amount as full_amount from employees e join variables_details v on
e.emp_id = v.emp_ref_id join designation d on v.emp_ref_id=d.emp_ref_id) as t1
where t1.emp_ref_id in (select t1.emp_ref_id from t1 where full_amount = (select max(full_amount) from t1) or full_amount = (select min(full_amount)
from t1 limit 1 offset 1);
but the query throwed an error.
Later i decided to create a temporary table and then fetch the data from it. I used the below query:
create temporary table temp (select d.emp_ref_id , d.emp_title, e.salary+v.variables_amount as full_amount from employees e join
variables_details v on e.emp_id = v.emp_ref_id join designation d on v.emp_ref_id=d.emp_ref_id);
select emp_title, full_amount from temp where full_amount = (select max(full_amount) from temp) or
full_amount = (select full_amount from temp order by full_amount asc limit 1 offset 1);
But it throwed an error stating "cant reopen table temp".
Both the methods did not work for me .
How should i approach this question?
Correct indentation helps finding the missing parentesis
In mysql 8 you can use the With clause to generate t1
Query #1
WITH t1 AS (select d.emp_ref_id , d.emp_title, e.salary+v.variables_amount as full_amount
from employees e join variables_details v on e.emp_id = v.emp_ref_id
join designation d on v.emp_ref_id=d.emp_ref_id)
select emp_title , emp_ref_id
from
t1
where t1.emp_ref_id in (select
t1.emp_ref_id
from t1
where full_amount = (select max(full_amount) from t1)
or full_amount = (select min(full_amount)
from t1 limit 1 offset 1)
);
emp_title
emp_ref_id
Asst.Manager
1
View on DB Fiddle
With temporary tables this whole becomes more complicated
CREATE TEMPORAry table t1 (select d.emp_ref_id , d.emp_title, e.salary+v.variables_amount as full_amount
from employees e join variables_details v on e.emp_id = v.emp_ref_id
join designation d on v.emp_ref_id=d.emp_ref_id);
CREATE TEMPORAry table t2 SELECT * FROM t1;
CREATE TEMPORAry table t3 SELECT * FROM t1;
CREATE TEMPORAry table t4 SELECT * FROM t1;
select emp_title , emp_ref_id
from
t1
where emp_ref_id in (select
emp_ref_id
from t2
where full_amount = (select max(full_amount) from t3)
or full_amount = (select min(full_amount)
from t4 limit 1 offset 1)
);
emp_title | emp_ref_id
:----------- | ---------:
Asst.Manager | 1
drop TEMPORAry table t1;
drop TEMPORAry table t2;
drop TEMPORAry table t3;
drop TEMPORAry table t4;
db<>fiddle here

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.

How to write query for left join

i have written left join query and i want the product_code column of left table should be updated by the product_code column of right table by the condition of below query
update stock_details_mt as s left join
(select min(product_code),product_name,mrp,sales_rate from stock_details_mt group by product_name,mrp,sales_rate having count(*)>1)as s2 set
s.product_code=s2.product_code on s.product_name=s2.product_name where s.mrp=s2.mrp and s.sales_rate=s2.sales_rate ;
You seem to have lost the plot between the join and set and I would be suspicious of the left join. Try this.
update stock_details_mt as s join
(select min(product_code) product_code,product_name,mrp,sales_rate
from stock_details_mt
group by product_name,mrp,sales_rate
having count(*)>1) as s2
on s.product_name=s2.product_name and s.mrp=s2.mrp and s.sales_rate=s2.sales_rate
set s.product_code=s2.product_code
where 1 = 1;
So given
drop table if exists stock_details_mt;
create table stock_details_mt
(product_code int, product_name varchar(10), mrp int, sales_rate int);
insert into stock_details_mt values
(2,'aaa',1,1),(1,'aaa',1,1),(10,'aaa',1,1),
(10,'bbb',1,1);
Result
+--------------+--------------+------+------------+
| product_code | product_name | mrp | sales_rate |
+--------------+--------------+------+------------+
| 1 | aaa | 1 | 1 |
| 1 | aaa | 1 | 1 |
| 1 | aaa | 1 | 1 |
| 10 | bbb | 1 | 1 |
+--------------+--------------+------+------------+
4 rows in set (0.00 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 |

Query MySQL Group by and Having

I am creating an application for my school and I am in trouble constructing the right query.
I have 2 tables,table1 and table2.
table1
---------------------------------------------------------
| StudentID | SubjectID | Present | Type |
---------------------------------------------------------
| 2 | 3 | yes | 1 |
| 2 | 2 | yes | 2 |
| 3 | 1 | no | 3 |
---------------------------------------------------------
table2
---------------------------------------------------------
| SubjectID | SubjectName | Number1 | Number2 |
---------------------------------------------------------
| 1 | Name1 | 6 | 4 |
| 2 | Name2 | 4 | 8 |
| 3 | Name3 | 5 | 2 |
---------------------------------------------------------
SubjectID in table1 is foreign key references table2.
I want to build a query sql that gives me the StudentID`s from table1
that didnt miss any Type 3 subject (i.e no row like this
---------------------------------------------------------
| StudentID | SubjectID | Present | Type |
---------------------------------------------------------
| 3 | 1 | no | 3 |
---------------------------------------------------------
And have completed 75 percent of type 1 (i.e
I find it like this
SELECT t1.StudentID,t1.SubjectID ,t1.Type,t2.Number1 as num
FROM table1 as t1,table2 as t2
WHERE t1.Present=yes and t2.SubjectID=t1.SubjectID
GROUP BY StudentID,SubjectID
HAVING COUNT(*)/num >= 75/100
But I cant combine the two things together.
You can combine queries by giving them aliases and joining as subqueries...
SELECT finisher.StudentID FROM
(
SELECT DISTINCT StudentID
FROM table1 t1
JOIN table2 t2 ON t2.SubjectID = t1.SubjectID
WHERE t1.Present = 'yes' AND t1.Type1 = 1
GROUP BY t1.StudentID, t2.SubjectID
HAVING COUNT(*) / t2.Number2 >= 0.75
) finisher
JOIN
(
SELECT DISTINCT t1.StudentID
FROM table1 t1
LEFT JOIN
(
SELECT DISTINCT StudentID
FROM table1
WHERE Type = 3 AND Present = 'no'
) missed ON missed.StudentID = t1.StudentID
WHERE t1.Type = 3
AND missed.StudentID IS NULL
) notmissed ON finisher.StudentID = notmissed.StudentID
"StudentID`s from table1 that didnt miss any Type 3"... I assume here you don't want to include students without any type 3 rows.
Seems like this is done and duste, but how about...
SELECT x.*
FROM
( SELECT t1.StudentID
, t1.SubjectID
, t1.Type
, t2.Number1 num
FROM table1 t1
JOIN table2 t2
ON t2.SubjectID=t1.SubjectID
WHERE t1.Present='yes'
GROUP
BY t1.StudentID
, t1.SubjectID
HAVING COUNT(*)/num >= 0.75
) x
LEFT
JOIN table1 y
ON y.student_id = x.student_id
AND y.subject_id = x.subject_id
AND y.type = 3
AND y.present = 'no'
WHERE y.student_id IS NULL;