Need to join two tables as per result of Group_concat - mysql

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`, '%')

Related

MySQL: Multi Tables - One to many relationship, Get column whose one of child's column is not null

I need help in creating sql query.
I want to get all orders whose none of child's res_id is null.
In the below example you will see order_audit.order_id W1 have one to
many relationship temp_order_id W1_1 and W1_2. This temp_order_id has further res_id 12 and 32. This order W1 should be in response.
In case of W2 you can see W2_1 has resp_id null. So this should not be pulled.
order_audit
+----+----------+
| id | order_id |
+----+----------+
| 1 | W1 |
| 2 | W2 |
| 2 | W3 |
+----+----------+
order_mapping
+----------+---------------+
| order_id | temp_order_id |
+----------+---------------+
| W1 | W1_1 |
| W1 | W1_2 |
| W2 | W2_1 |
| W2 | W2_2 |
| W3 | W3_1 |
+----------+---------------+
temp_order_table
+---------------+--------+
| temp_order_id | res_id |
+---------------+--------+
| W1_1 | 12 |
| W1_2 | 32 |
| W2_1 | null |
| W2_2 | 33 |
| W3_1 | null |
+---------------+--------+
From you screenshot it looks like there is a leading space in Account (and maybe there are trailing ones as well).
Any kind of help would be appreciated
You can natural join all 2 other tables and check for if res_id is null.
select oa.id, oa.order_id from order_audit oa
where not exists (
select * from order_mapping om
join temp_order_table tot on
tot.temp_order_id = om.temp_order_id
where om.order_id = oa.order_id and tot.res_id is null
)
Here is the link for sqlfiddle link
You could use a NOT IN forn the order with null
select oa.order_id
from order_audit oa
where oa.order_id NOT IN (
select om.order_id
from order_mapping om
inner join (
select to.temp_order_id
from temp_order_table to
where to.res_id is null
) t on t.temp_order_id = om.temp_order_id
)
I would approach this using group by and having:
select om.order_id
from order_mapping om left join
temp_order_table tot
on om.temp_order_id = tot.temp_order_id
group by om.order_id
having count(tot.temp_order_id) = count(tot.res_id);

MySQL - How get this result?

I have a two tables.
work:
+----+----------+
| id | position |
+----+----------+
| 1 | 1 |
| 2 | 2 |
+----+----------+
content:
+----+---------+------+-------------+
| id | work_id | name | translation |
+----+---------+------+-------------+
| 1 | 1 | Kot | 1 |
| 2 | 1 | Cat | 2 |
| 3 | 2 | Ptak | 1 |
| 4 | 2 | Bird | 2 |
| 5 | 2 | Ssss | 3 |
+----+---------+------+-------------+
I want to get result like this:
+----+------+----------+
| id | name | sortName |
+----+------+----------+
| 1 | Kot | NULL |
| 1 | Cat | NULL |
| 2 | Ptak | Ssss |
| 2 | Bird | Ssss |
+----+------+----------+
My not working query is here:
select
w.id,
c.name,
cSort.name as sortName
from
work w
LEFT JOIN
content c
ON
(w.id=c.work_id)
LEFT JOIN
content cSort
ON
(w.id=cSort.work_id)
WHERE
c.translation IN(1,2) AND
cSort.translation=3
ORDER BY
sortName
I want to get for each work at least one translation and secound if exist (translation=1 always exist). And for every row I want special column with translation used to sort. But Not always this translation exist for work.id. In this example I want to sort work by translation=3.
Sorry for my not fluent english. Any ideas?
Best regards
/*
create table work ( id int, position int);
insert into work values
( 1 , 1 ),
( 2 , 2 );
create table content(id int, work_id int, name varchar(4), translation int);
insert into content values
( 1 , 1 , 'Kot' , 1),
( 2 , 1 , 'Cat' , 2),
( 3 , 2 , 'Ptak' , 1),
( 4 , 2 , 'Bird' , 2),
( 5 , 2 , 'Ssss' , 3);
*/
select w.id,c.name,(select c.name from content c where c.work_id = w.id and c.translation = 3) sortname
from work w
join content c on w.id = c.work_id
where c.translation <> 3;
result
+------+------+----------+
| id | name | sortname |
+------+------+----------+
| 1 | Kot | NULL |
| 1 | Cat | NULL |
| 2 | Ptak | Ssss |
| 2 | Bird | Ssss |
+------+------+----------+
So translation is also a work_id and you consider translation = 3 a translation in your example and translation <> 3 an original. You want to join each original record with every translation record where the latter's work_id matches the former's translation.
I think you are simply confusing IDs here. It should be ON (w.translation = cSort.work_id).
Another way to write the query:
select o.work_id as id, o.name, t.name as sortname
from (select * from content where translation <> 3) o
left join (select * from content where translation = 3) t
on t.work_id = o.translation
order by t.name;
There seems to be no need to join table work.
I'd like to add that the table design is a bit confusing. Somehow it is not clear from it what is a translation for what. In your example you interpret translation 3 as a translation for the non-three records, but this is just an example as you say. I don't find this readable.
UPDATE: In order to sort your results by work.position, you can join that table or use a subquery instead. Here is the order by clause for the latter:
order by (select position from work w where w.id = o.work_id);

Mysql select query with condition

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)

Merge two row results into one row MYSQL

I have a table having following structure:
| pid | email | email_type |
| 1 | x | 1 |
| 1 | y | 2 |
| 1 | z | 3 |
| 2 | ab | 1 |
| 3 | cd | 2 |
Now I want my result for the pid parameter in format for email_type[1 & 2] only:
Case pid=1
| pid | email_p | email_w |
| 1 | x | y |
Case pid=2
| 2 | ab | NULL |
Case pid=3
| 3 | NULL | cd |
Here email_p represents email_type=1 & email_w represents email_type=2
I am using following query, and its working fine except for a case pid=2. Case I & Case III are successfully fetched. Please provide some solution with good explanation(if possible).
SELECT `e`.`pid`, `e`.`email` AS `email_p`, `e1`.`email` AS `email_w` FROM `table1` AS `e` LEFT JOIN `table1` AS `e1` ON e.pid=e1.pid AND e1.email_type=2 WHERE (e.pid IN (1) AND e.email_type=1)
It fails when e.pid = 2 and it returns empty result set & please provide solution e.pid IN (1,2,3) holds good for required format.#MYSQL
Try This
SELECT pid,
MAX(CASE WHEN email_type=1 THEN email END ) as email_p ,
MAX(CASE WHEN email_type=2 THEN email END ) as email_w
FROM tableName
WHERE email_type IN (1,2)
GROUP BY pid
SQL Fiddle DEMO

Order MySQL data by row value

I have two tables that looks like this:
Table: items
id | itemId
---|------
0 | 1
1 | 2
2 | 3
Table: item_specs
id | itemId | key | values
---|--------|---------------
0 | 1 | itemreceived | 2012-06-01
1 | 1 | modelyear | 1992
2 | 1 | model | 2
3 | 2 | itemreceived | 2012-06-05
4 | 2 | modelyear | 2003
5 | 2 | model | 1
6 | 3 | itemreceived | 2012-07-05
7 | 3 | modelyear | 2000
8 | 3 | model | 3
My current query looks like this:
SELECT items.*, item_specs.* FROM item_specs
INNER JOIN item_specs ON items.itemId = item_specs.itemId
WHERE itemId IN(1,2,3)
How can I order the result by a key value, for example: model?
The result I'm looking for is something like this: (if I order by model)
id | itemId | key | values
---|--------|---------------
3 | 2 | itemreceived | 2012-06-05
4 | 2 | modelyear | 2003
5 | 2 | model | 1
0 | 1 | itemreceived | 2012-06-01
1 | 1 | modelyear | 1992
2 | 1 | model | 2
6 | 3 | itemreceived | 2012-07-05
7 | 3 | modelyear | 2000
8 | 3 | model | 3
The content that is returned is ordered by the value that is that has the key model
You need the model number for every row. You can do that with a join:
SELECT items.*, item_specs.*
FROM item_specs
INNER JOIN item_specs ON items.itemId = item_specs.itemId
INNER JOIN item_specs aux ON (aux.key = 'model' and aux.itemID = item_specs.itemId)
WHERE item_specs.itemId IN(1,2,3)
ORDER BY aux.values/*this is the model*/, item_specs.id;
or with a subselect:
SELECT items.*,
item_specs.*,
(select aux.values
from item_specs aux
where aux.key = 'model' and aux.itemID = item_specs.itemId
) as model
FROM item_specs
INNER JOIN item_specs ON items.itemId = item_specs.itemId
WHERE item_specs.itemId IN(1,2,3)
ORDER BY model, item_specs.id;
SELECT * FROM `table` WHERE `key` = 'model' ORDER BY `values` ASC
You have to manually specify a table type/storage engine. That can't be seen in the structure you provided.
Read more here.
It seems you want to use an order by clause. This will order by the columns you need. You can also do sneaky things here, like insert a true/false value for what you order by first.
SELECT * FROM `table`
Order by (case When Key='model' then 0 else 1 end), values
See, for instance, http://blog.sqlauthority.com/2007/07/17/sql-server-case-statement-in-order-by-clause-order-by-using-variable/
SELECT * FROM `table`
WHERE `key` = 'model'
ORDER BY `values`;