repeated values with group_concat and joins - mysql

i have a little problem with the following Query. It returns multiple values.
Here is the result I'm receiving:
+----+--------------+--------+--------+---------------------+----------+------------------+
| id | company | county | vm | os | products | sn |
+----+--------------+--------+--------+---------------------+----------+------------------+
| 1 | ABC Corp | USA | VMW | Linux, Linux, Linux | 3 | A123, B234, A343 |
| 2 | DEF Corp | USA | CIT | Windows | 1 | I223 |
+----+--------------+--------+--------+---------------------+----------+------------------+
As you can see, the first line shows 3 times Linux, but this should be only listed once. I've seen that this problem only occurs if the customer has more than 1 product. I think i have to Group my Query or something like this, but i don't know how.
Here is my Query:
SELECT
customer.id,
customer.company,
countries.en AS country,
vmenv.name AS vm,
GROUP_CONCAT(operatingsystems.name SEPARATOR ', ') AS os,
COUNT(device2customer.sn) AS products,
GROUP_CONCAT(device2customer.sn SEPARATOR ', ') AS sn
FROM
customer
LEFT JOIN
countries
ON
customer.country = countries.id
LEFT JOIN
vmenv2kunden
ON
vmenv2kunden.customerid = customer.id
LEFT JOIN
vmenv
ON
vmenv2kunden.vmenvnr = vmenv.id
LEFT JOIN
operatingsystems2customer
ON
operatingsystems2customer.customerid = customer.id
LEFT JOIN
operatingsystems
ON
operatingsystems2customer.osnr = operatingsystems.id
LEFT JOIN
device2customer
ON
device2customer.kundenid = customer.id
GROUP BY
customer.id

In your query change the group_concat statement to
GROUP_CONCAT(DISTINCT operatingsystems.name SEPARATOR ', ') AS os,
COUNT(DISTINCT device2customer.sn) AS products,
GROUP_CONCAT(DISTINCT device2customer.sn SEPARATOR ', ') AS sn
By adding the DISTINCT key word it should work for you

you just need yo use distinct in Group_concat.
Please try the below updated Query.
SELECT
customer.id,
customer.company,
countries.en AS country,
vmenv.name AS vm,
GROUP_CONCAT(distinct operatingsystems.name SEPARATOR ', ') AS os,
COUNT(device2customer.sn) AS products,
GROUP_CONCAT(device2customer.sn SEPARATOR ', ') AS sn
FROM
customer
LEFT JOIN
countries
ON
customer.country = countries.id
LEFT JOIN
vmenv2kunden
ON
vmenv2kunden.customerid = customer.id
LEFT JOIN
vmenv
ON
vmenv2kunden.vmenvnr = vmenv.id
LEFT JOIN
operatingsystems2customer
ON
operatingsystems2customer.customerid = customer.id
LEFT JOIN
operatingsystems
ON
operatingsystems2customer.osnr = operatingsystems.id
LEFT JOIN
device2customer
ON
device2customer.kundenid = customer.id
GROUP BY
customer.id

Related

MySQL select group concat?

I am trying to do a select from two tables. I have two tables:
select * from igw41_users;
+-----+------------+----------+-----------------------------+--------------------------------------------------------------+-------+-----------+---------------------+---------------------+------------+--------------------------------------------------------------------------------------------------------------------------------+---------------------+------------+--------+------+--------------+
| id | name | username | email | password | block | sendEmail | registerDate | lastvisitDate | activation | params | lastResetTime | resetCount | otpKey | otep | requireReset |
17 John Doe AAAAAA nothing else is needed from this table.
select * from igw41_user_profiles;
+---------+----------------------+-----------------------+----------+
| user_id | profile_key | profile_value | ordering |
17 profile.account_type "2" 4
17 profile.postal_code "75055" 1
I need to get id (from igw41_users), username igw41_users , postal_code (from igw41_user_profiles) and account_type (from igw41_user_profiles). But the info I need is in profile_values for each igw41_user_profiles.user_id that matches igw41_users.id.
select id, username, GROUP_CONCAT(profile_value SEPARATOR ',')
from igw41_users
left join igw41_user_profiles on igw41_users.id = igw41_user_profiles.user_id and igw41_user_profiles.profile_key = 'profile.account_type'
group by username;
this gives me the account_type, but I can't figure out how to get the postal_code If I do a right join it gives me: ERROR 1066 (42000): Not unique table/alias: 'igw41_user_profiles'
This is what I tried to get both profile values:
select id, username, GROUP_CONCAT(profile_value SEPARATOR ',')
from igw41_users
left join igw41_user_profiles on igw41_users.id = igw41_user_profiles.user_id and igw41_user_profiles.profile_key = 'profile.account_type'
right join igw41_user_profiles on igw41_users.id = igw41_user_profiles.user_id and igw41_user_profiles.profile_key = 'profile.postal_code'
group by username;
Thanks in advance.
take and igw41_user_profiles.profile_key = 'profile.account_type' out of your first query
If you wish to test for both use in
and igw41_user_profiles.profile_key in('profile.account_type','profile.postal_code')
In common way when you need to join same table more then once you need to use aliases for each join:
select id, username, GROUP_CONCAT(profile_value SEPARATOR ',')
from igw41_users
left join igw41_user_profiles p1
on igw41_users.id = p1.user_id and
p1.profile_key = 'profile.account_type'
right join igw41_user_profiles p2
on igw41_users.id = p2.user_id and
p2.profile_key = 'profile.postal_code'
group by username;
In this case the second join is redundant:
select id, username, GROUP_CONCAT(profile_value SEPARATOR ',')
from igw41_users
left join igw41_user_profiles p1 on igw41_users.id = p1.user_id
where
p1.profile_key = 'profile.account_type' OR
p1.profile_key = 'profile.postal_code'
group by username;

SQL WHERE IN with Left Join is not returning all rows I expect

I'm building a little conjugation/radicalization app, and I have stumbled upon a problem. I have this SQL request:
SELECT DISTINCT RA.*
FROM radical RA
left join conjugated CO
on CO.word_id = RA.id
where CO.conjugation IN ('I', 'am', 'a', 'cat')
That returns:
| id | radical |
| 13 | to be |
However, I would like to get a result of the type:
| id | radical | word |
| null | null | I |
| 13 | to be | am |
| null | null | a |
| null | null | cat |
Does anyone know how?
You need a left join, but to start with all the words you want to keep:
select w.word, ra.*
from (select 'I' as word union all
select 'am' union all select 'a' union all select 'cat'
) w left join
conjugated co
on co.conjugation = w.word left join
radical ra
on ra.id = co.word_id;
If these values are in conjugation, you can simply do:
select c.onjugation, ra.*
from conjugated co left join
radical ra
on ra.id = co.word_id
where c.conjugation in ('I', 'am', 'a', 'cat') ;
That is, conjugation should be first, because you want to keep all matching rows in that table.
Seemingly you are using a Left Join, when you actually need a Right join (since it appears you want all rows of the right table matching the predicate to be returned)
So either switch the join:
SELECT DISTINCT RA.*, co.`conjugated` as word
FROM radical RA
right join conjugated CO
on CO.word_id = RA.id
where CO.conjugation IN ('I', 'am', 'a', 'cat');
Or switch the order of the tables in the FROM:
SELECT DISTINCT RA.*, co.`conjugated` as word
FROM conjugated CO
left join radical RA
on CO.word_id = RA.id
where CO.conjugation IN ('I', 'am', 'a', 'cat');

MySQL count subquery on same table

I have this query:
SELECT `facilities`.`name` AS facility, `countries`.`name` AS country, `states`.`name` AS state, `users`.`dosage` AS dosage, COUNT(`users`.`id`) AS registrations
FROM `users`
LEFT JOIN `countries` ON `users`.`country_id` = `countries`.`id`
LEFT JOIN `states` ON `users`.`state_id` = `states`.`id` LEFT JOIN `user_facilities` ON `users`.`id` = `user_facilities`.`user_id`
LEFT JOIN `facilities` ON `user_facilities`.`facility_id` = `facilities`.`id`
WHERE `users`.`dosage` != "Not sure"
GROUP BY `facilities`.`name`, `countries`.`name`, `states`.`name`, `users`.`dosage`
ORDER BY `facilities`.`id` ASC, `countries`.`id` ASC, `states`.`name` ASC
It gives me this result:
Hospital | United States | Arkansas | 10 doses | 3
Hospital | United States | Arkansas | >10 doses | 4
Home care | United States | Arkansas | 10 doses | 1
Home care | United States | Texas | 10 doses | 1
My users table:
id | email | state_id | country_id | dosage | percent_completed
What I need to do is to get the number of users with percent_completed = 100 for each result. I tried subqueries, but I couldn't find the right subquery for this. I'm stuck. Does anyone have some piece of advice?
Thanks.
If I understand correctly, you can use conditional aggregation. In MySQL you can just do:
select . . .,
sum(percent_completed = 100) as num_at_100
After group by please add the " having sum(percent_completed) >=100 " that will will you users count who are completed > =100 percent
SELECT `facilities`.`name` AS facility, `countries`.`name` AS country, `states`.`name` AS state, `users`.`dosage` AS dosage, COUNT(`users`.`id`) AS registrations
FROM `users`
LEFT JOIN `countries` ON `users`.`country_id` = `countries`.`id`
LEFT JOIN `states` ON `users`.`state_id` = `states`.`id` LEFT JOIN `user_facilities` ON `users`.`id` = `user_facilities`.`user_id`
LEFT JOIN `facilities` ON `user_facilities`.`facility_id` = `facilities`.`id`
WHERE `users`.`dosage` != "Not sure"
GROUP BY `facilities`.`name`, `countries`.`name`, `states`.`name`, `users`.`dosage` having sum(users.percentage_completed) >= 100
ORDER BY `facilities`.`id` ASC, `countries`.`id` ASC, `states`.`name` ASC

Mysql nested select with multiple joins with condition on join table

I've got a SELECT with multiple JOINS for a paginated Tableview. In general this is working for unfiltered results.
The query looks like this:
SELECT seltable.*,
tbl2.name AS tbl2name,
tbl3.name AS tbl3name,
tbl4.name AS tbl4name
FROM
( SELECT * FROM selecttable
WHERE value = 99
ORDER BY datetime DESC
LIMIT 50 OFFSET 0 )
AS seltable
LEFT JOIN table1 AS tbl1 ON seltable.tbl1_uid = tbl1.uid
LEFT JOIN table2 AS tbl2 ON tbl1.tbl2_uid = tbl2.uid
LEFT JOIN table3 AS tbl3 ON tbl2.tbl3_uid = tbl3.uid
LEFT JOIN table4 AS tbl4 ON tbl3.tbl4_uid = tbl4.uid;
Now I've got no clue how to accomplish filtering the results with a condition related to one of the join tables.
When I just set a:
LEFT JOIN tablex AS table ON foreign_table.tblx_uid = table.uid AND {condition}
this condition regards only to the 50 results of the nested SELECT.
Is there any way to achieve using WHERE clauses on the JOIN tables in this scenario?
For sample data see http://sqlfiddle.com/#!2/fad4d/2
Expected results:
to get x team records limited to 5 team uids, where Tournament2 is one of the related tournaments for the team.
Best regards
w1ll1
Try not controlling the pagination in that subquery, instead just use a more conventional query with a composite where clause. HOWEVER, because you are using left joins take care adding filters through the where clause that would override the outer join to produce the effect of an inner join.
SELECT seltable.*,
tbl2.name AS tbl2name,
tbl3.name AS tbl3name,
tbl4.name AS tbl4name
FROM selecttable AS seltable
LEFT JOIN table1 AS tbl1 ON seltable.tbl1_uid = tbl1.uid
LEFT JOIN table2 AS tbl2 ON tbl1.tbl2_uid = tbl2.uid
LEFT JOIN table3 AS tbl3 ON tbl2.tbl3_uid = tbl3.uid
LEFT JOIN table4 AS tbl4 ON tbl3.tbl4_uid = tbl4.uid
WHERE seltable.value = 99
...
ORDER BY seltable.datetime DESC
LIMIT 50 OFFSET 0
Alternatively use more subqueries, like this:
SELECT seltable.*,
tbl2.name AS tbl2name,
tbl3.name AS tbl3name,
tbl4.name AS tbl4name
FROM
( SELECT * FROM selecttable
WHERE value = 99
ORDER BY datetime DESC
LIMIT 50 OFFSET 0 )
AS seltable
LEFT JOIN ( SELECT uid, name
FROM table1
WHERE 1=1 -- amend to suit
) AS tbl1 ON seltable.tbl1_uid = tbl1.uid
LEFT JOIN ( SELECT uid, name
FROM table2
WHERE 1=1 -- amend to suit
) AS tbl2 ON tbl1.tbl2_uid = tbl2.uid
LEFT JOIN ( SELECT uid, name
FROM table3
WHERE 1=1 -- amend to suit
) AS tbl3 ON tbl2.tbl3_uid = tbl3.uid
LEFT JOIN ( SELECT uid, name
FROM table4
WHERE 1=1 -- amend to suit
) AS tbl4 ON tbl3.tbl4_uid = tbl4.uid;
Here is another attempt, based on your sqlfiddle it appears that INNER JOINS may be used:
SELECT theteam.*,
trnmnt.name AS tournamentname,
cat.name AS categoryname,
sport.name AS sportname
FROM (
SELECT * FROM team
ORDER BY team.name ASC )
AS theteam
INNER JOIN tournament_team AS tntm ON tntm.team_uid = theteam.uid
INNER JOIN tournament AS trnmnt ON tntm.tournament_uid = trnmnt.uid AND trnmnt.name = 'Tournament2'
INNER JOIN category AS cat ON trnmnt.category_uid = cat.uid
INNER JOIN sport ON cat.sport_uid = sport.uid
LIMIT 5 OFFSET 0
;
The result of that query is:
| UID | NAME | TOURNAMENTNAME | CATEGORYNAME | SPORTNAME |
|-----|--------|----------------|--------------|-----------|
| 2 | Team02 | Tournament2 | Germany | Soccer |
| 3 | Team03 | Tournament2 | Germany | Soccer |
| 4 | Team04 | Tournament2 | Germany | Soccer |
| 5 | Team05 | Tournament2 | Germany | Soccer |
| 6 | Team06 | Tournament2 | Germany | Soccer |

Joining two tables by id in mysql

I have two tables like this:
Table_users
id | firstname | lastname
1 | John | Doe
2 | Eve | Adam
table_shifts
date | dayshift | nightshift
2014-09-17 | 1 | 2
2014-09-18 | 2 | 1
And I want this as a result:
table_shifts_overview
date | dayshift | nightshift
2014-09-17 | John Doe | Eve Adam
Where date = '2014-09-17'
I tried this with with JOIN and a subquery, but it didn't work out. Any halp would be appreciated.
Try this query
SELECT TS.date, CONCAT(TU1.firstname,' ', TU1.lastname) AS dayshift, CONCAT(TU2.firstname, ' ', TU2.lastname) AS nightshift
FROM table_shifts TS
INNER JOIN table_users TU1 on TU1.ID= TS.dayShift
INNER JOIN table_users TU2 on TU2.id= TS.NightShift
WHERE TS.Date = '2014-09-17'
SELECT S.date,
concat(U1.FirstName,' ', U1.LastName) dayshift,
concat(U2.FirstName,' ', U2.LastName) nightshift
FROM table_Shifts S
INNER JOIN table_users U1
on U1.ID= S.dayShift
INNER JOIn table_users U2
on U2.id= S.NightShift
WHERE S.Date = '2014-09-17'
You can join the same table multiple times by aliasing it:
SELECT date, u1.firstname, u1.lastname, u2.firstname, u2.lastname
FROM table_shifts
INNER JOIN table_users AS u1 ON u1.id = dayshift.id
INNER JOIN table_users AS u2 ON u2.id = nightshift.id
You can use implicit join:
SELECT s.date,
CONCAT(u_day.firstname, ' ', u_day.lastname) AS dayshift,
CONCAT(u_night.firstname, ' ', u_night.lastname) AS nightshift
FROM shifts s, users u_day, users u_night
WHERE s.dayshift = u_day.id AND s.nightshift = u_night.id
AND s.date = '2014-09-17'
Or explicit join:
SELECT s.date,
CONCAT(u_day.firstname, ' ', u_day.lastname) AS dayshift,
CONCAT(u_night.firstname, ' ', u_night.lastname) AS nightshift
FROM shifts s
INNER JOIN users u_day ON (s.dayshift = u_day.id)
INNER JOIN users u_night ON (s.nightshift = u_night.id)
WHERE s.date = '2014-09-17'
Note that the keyword INNER is optional in the last query.
Here is the MySQL documentation about JOIN syntax:
http://dev.mysql.com/doc/refman/5.6/en/join.html
You can try;
SELECT ts.date,
contact(tu.firstname ,' ', tu.lastname) AS dayshift,
contact(tu2.firstname ,' ', tu2.lastname) AS nightshift
FROM table_shifts ts, Table_users tu, Table_users tu2
WHERE ts.dayshift = tu.id AND
ts.nighshift = tu2.id AND
ts.date = '2014-09-17'