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
Related
I have two tables, table1 and table2.
Example of the table1 table.
^ invoice ^ valid ^
| 10 | yes |
| 11 | yes |
| 12 | no |
Example of the table2 table
^ invoice ^ detail ^
| 10 | A |
| 10 | C |
| 10 | F |
| 11 | A |
| 11 | F |
| 10 | E |
| 12 | A |
Want to select from table 2 all rows that:
Have a valid invoice in table 1
And enumerate:
the detail for each invoice
the invoice
Here the desired result
^ invoice ^ detail ^ ordination ^ ordinationb ^
| 10 | A | 1 | 1 |
| 10 | C | 2 | 1 |
| 10 | F | 3 | 1 |
| 11 | A | 1 | 2 |
| 11 | F | 2 | 2 |
| 10 | E | 4 | 1 |
The sentence should valid for use in phpMyAdmin 4.8.4
Here is the MySQL 8+ way of doing this:
SELECT
t2.Invoice,
t2.`lines`,
ROW_NUMBER() OVER (PARTITION BY t2.Invoice ORDER BY t2.`lines`) line_order,
DENSE_RANK() OVER (ORDER BY t2.Invoice) ordination
FROM table2 t2
WHERE EXISTS (SELECT 1 FROM table1 t1 WHERE t1.Invoice = t2.Invoice AND t1.valid = 'yes');
Demo
If you are using a version of MySQL earlier than 8, then you might have to resort to using session variables. This can lead to an ugly query. If you have a long term need for queries like this one, then I recommending upgrading to MySQL 8+.
Edit:
It just dawned on me that we can use correlated subqueries to simulate both your ROW_NUMBER and DENSE_RANK requirements. Here is one way to do this query in MySQL 5.7 or earlier:
SELECT
t2.Invoice,
t2.detail,
(SELECT COUNT(*) FROM table2 t
WHERE t.Invoice = t2.Invoice AND t.detail <= t2.detail) ordination,
t.dr AS ordinationb
FROM table2 t2
INNER JOIN
(
SELECT DISTINCT
t2.Invoice,
(SELECT COUNT(*)
FROM (SELECT DISTINCT Invoice FROM table2) t
WHERE t.Invoice <= t2.Invoice) dr
FROM table2 t2
) t
ON t.Invoice = t2.Invoice
WHERE EXISTS (SELECT 1 FROM table1 t1 WHERE t1.Invoice = t2.Invoice AND t1.valid = 'yes')
ORDER BY
t2.Invoice,
t2.detail;
Demo
I have a problem joining the following tables in that Table 1 conatins all specialists ie
John (id1)
Pete (id2)
Harry (id3)
Joanne (id4)
etc
Table 2 is only populated when a specialist has availability on a certain day ie
id1 2018-10-19
id3 2018-10-19
The results I need from the MySQL query when I use the where statement table2.date=2018-10-19 is
John 2018-10-19
Pete
Harry 2018-10-19
Joanne
but what I actually get is
John 2018-10-19
Harry 2018-10-19
which is correct but I need all specialists to show in order.
Can any one help with any suggestions please
Unless your question is not a good one (and I suspect that it may be a bad one) you don't need the where statement. So
drop table if exists t1,t2;
create table t1 (id int,val varchar(10));
insert into t1 values
(1,'John' ),
(2,'Pete' ),
(3,'Harry'),
(4,'Joanne');
create table t2(t1id int,dt date);
insert into t2 values
(1 ,'2018-10-19'),
(3 ,'2018-10-19');
SELECT * from t1
LEFT OUTER JOIN t2 ON t1.id = t2.t1id
order by t1.val;
Result
+------+--------+------+------------+
| id | val | t1id | dt |
+------+--------+------+------------+
| 3 | Harry | 3 | 2018-10-19 |
| 4 | Joanne | NULL | NULL |
| 1 | John | 1 | 2018-10-19 |
| 2 | Pete | NULL | NULL |
+------+--------+------+------------+
4 rows in set (0.00 sec)
I have no idea how you would get johns,pete,harry,joanne in your result set if you wish to order by name value.
And '"&request.querystring("d")&"' is not mysql what is this php maybe?
If you are interested in the availability or otherwise for a specific date you would first cross join(creating a cartesian product) specialists to date(s) for example
select t1.id,t1.val,dt
from t1
cross join (select '2018-10-19' dt
#union all select '2018-10-20'
) s;
+------+--------+------------+
| id | val | dt |
+------+--------+------------+
| 1 | John | 2018-10-19 |
| 2 | Pete | 2018-10-19 |
| 3 | Harry | 2018-10-19 |
| 4 | Joanne | 2018-10-19 |
+------+--------+------------+
4 rows in set (0.00 sec)
and then see if they exist in table2
select t.id,t.val,t.dt tdt , ifnull(t2.dt,'Not Available') t2dt
from
(select t1.id,t1.val,dt
from t1
cross join (select '2018-10-19' dt
#union all select '2018-10-20'
) s
) t
left join t2
on t.id = t2.t1id and t2.dt = t.dt
order by t.dt,val;
+------+--------+------------+---------------+
| id | val | tdt | t2dt |
+------+--------+------------+---------------+
| 3 | Harry | 2018-10-19 | 2018-10-19 |
| 4 | Joanne | 2018-10-19 | Not Available |
| 1 | John | 2018-10-19 | 2018-10-19 |
| 2 | Pete | 2018-10-19 | Not Available |
+------+--------+------------+---------------+
Note you can have any number of dates in the cross join by using union. I have 2018-10-20 commented out.
If you have a large range of dates union may become unwieldy and creating a calendar/dates table in your db may be useful and you would substitute that in the cross join. for example
select t.id,t.val,t.dt tdt , ifnull(t2.dt,'Not Available') t2dt
from
(select t1.id,t1.val,dt
from t1
cross join (select dte dt from dates where dte between '2018-10-19' and '2018-10-19'
) s
) t
left join t2
on t.id = t2.t1id and t2.dt = t.dt
order by t.dt,val;
You can of course amend the cross join where condition to whatever you want.
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)
TABLE 1
+----+--------+-----+
| id | userId |state|
+----+--------+-----+
| 1 | 1 |AZ |
| 2 | 1 |AK |
| 4 | 1 |AL |
| 5 | 1 |CO |
| 6 | 1 |CA |
| 7 | 2 |AZ |
| 8 | 2 |AK |
| 9 | 2 |AL |
+----+--------+-----+
TABLE 2
+----+---------+--------+
| id | job | from | to |
+----+------+------+----+
| 1 | job1 | AZ |AK |
| 2 | job2 | AL |CO |
+----+---------+--------+
I want list of Job as per their to & from both state allowed by user in mysql, For above it will return
+------+--------+
| userId | job |
+--------+------+
| 1 | job1 | // As User 1 will have state AZ & AK
| 1 | job2 | // As User 1 will have state AL & CO
| 2 | job1 | // As User 2 will have state AZ & AK
+----+----------+
used query:
SELECT hs.userId, j.job FROM `table2` j
JOIN (
SELECT userId,GROUP_CONCAT(CONCAT('\'', `state`, '\'' )) as stateList FROM `table1` GROUP BY userId
) hs ON j.`to` IN (stateList) AND j.`from` IN (stateList)
Joining twice should be faster than using a group_concat:
SELECT u1.userId, j.job
FROM `table2` j
JOIN `table1` u1 ON u1.state = j.from
JOIN `table1` u2 ON u2.state = j.to AND u2.userId = u1.userId
It's been a little while since I used mysql, but if the IN clause works similar to MS SQL Server then it does not work with a comma-separated string argument, the comma separation must be outside of the string. You would need to use a string comparison instead (the LIKE operator for example).
SELECT hs.userId, j.job FROM `table2` j
JOIN (
SELECT userId,GROUP_CONCAT(CONCAT('\'', `state`, '\'' )) as stateList FROM `table1` GROUP BY userId
) hs ON stateList LIKE CONCAT('%', j.`to`, '%') AND stateList LIKE CONCAT('%', j.`from`, '%')
I have a Mysql table with the following data.
|ID | Date | BillNumber|BillMonth | Amount | Name |AccNum |
| 2 |2015-09-25| 454345 | 092015 | 135.00 |Andrew Good| 735976|
| 3 |2015-09-26| 356282 | 092015 | 142.00 |Peter Pan | 123489|
| 4 |2015-08-11| 312738 | 082015 | 162.00 |Andrew Good| 735976|
| 5 |2015-07-12| 287628 | 072015 | 220.67 |Andrew Good| 735976|
| 6 |2015-06-12| 100756 | 062015 | 556.34 |Andrew Good| 735976|
What I wanted to achieve is to retrieve the data of Andrew Good with AccNum 735976 for the BillMonth of 092015, provided that the user can entry any of his BillNumber(past/current).
If the reason that that row is of interest is because it is the latest of his rows, try:
select *
from tbl t
where name = ( select name
from tbl
where billnumber = 100756 -- can be any of his
)
and date = ( select max(date)
from tbl x
where x.name = t.name
)
(the billnumber can be any of his)