MySQL results by userd_id? - mysql

I have the following MySQL database table structure:
name | product | client_id
JOHN BROWN | test1.com | 122
JANE SMITH | hosting1 | 122
DAN JOHNSON | test2.com | 355
How to show mysql query results in php in order to get tables with results grouped by client_id. The main point is I need those details emailed by client_id, so in the current example I should get two separated tables fore those two clients.

Assuming your table is called signups
SELECT client_id,
GROUP_CONCAT(DISTINCT name_product_email
ORDER BY name_product_email DESC SEPARATOR ',')
FROM (
SELECT CONCAT(name, ' has this product: ', product) as name_product_email, client_id FROM signups)
GROUP BY client_id;

select client_id, group_concat(product)
from my_table
group by 1;
will produce output like:
122, "test1.com,hosting1"
355, "test2.com"
etc

Related

How to bring different values from results column into single row by value from other column sql

I have the following tables:
Teammate ID
Teammate name
Team id
Teams
1
Amy
11
Sales
1
Amy
12
Support
1
Amy
13
Marketing
2
Peter
12
Support
2
Peter
13
Marketing
And I want to group my results so the Teams column appears in one single row by Teammate Id or Teammate name as per below:
Teammate ID
Teammate name
Team id
Teams
1
Amy
11, 12, 13
Sales, Support, Marketing
2
Peter
12, 13
Support, Marketing
Which function would be best/cleanest to use for this purpose? I tried subqueries, coalescing, some weird XML path thing but as a new SQL user I can't wrap my head around figuring this one out
My original query which gave me the results is;
SELECT
tm.teammate_id AS "Teammate ID",
tm.name AS "Teammate name",
itt.team_id AS "Team IDs",
it.team AS "Teams"
FROM
intercom_teammates AS tm
LEFT JOIN intercom_teammate_teams AS itt
ON tm.teammate_id = itt.teammate_id
LEFT JOIN intercom_teams AS it
ON tm.teammate_id = itt.teammate_id
A simple group_concat would do the trick:
select it.TeammateID,
group_concat( distinct it.Teammatename SEPARATOR ',') as Teammatename,
group_concat( it.Teamid SEPARATOR ',') as Teamid,
group_concat( it.Teams SEPARATOR ',') as Teams
from intercom_teammates it
group by it.TeammateID ;
https://dbfiddle.uk/rU8-h8rX
Note. I used distinct on Teammatename, but I think it is excess and you can remove it if for every different TeammateID the Teammatename is unique.
SELECT
tm.teammate_id AS "Teammate ID",
tm.name AS "Teammate name",
GROUP_CONCAT(DISTINCT itt.team_id ORDER BY itt.team_id ASC) AS "Team IDs",
GROUP_CONCAT(DISTINCT it.team ORDER BY it.team DESC) AS "Teams"
FROM intercom_teammates tm
LEFT JOIN intercom_teammate_teams itt ON tm.teammate_id = itt.teammate_id
LEFT JOIN intercom_teams it ON tm.teammate_id = it.teammate_id
GROUP BY tm.teammate_id, tm.name
Note: I've corrected your JOIN to intercom_teams changing itt.teammate_id to it.teammate_id; it was throwing off the result set.
Result:
| Teammate ID | Teammate name | Team IDs | Teams |
|-------------|---------------|----------|--------------------------|
| 1 | Amy | 11,12,13 | Support,Sales,Marketing |
| 2 | Peter | 12,13 | Support,Marketing |
Fiddle here.

Get records of a table which exists in another table distinct field in MySQL

I have two tables
land_information
id | title_number | owner | case_no
1 001 John 201
2 002 Peter 202
3 002 Andrew 203
4 003 Mores 204
sheets
id | title_number
1 001
2 001
3 002
4 NULL
5 Unavailable
Now, I need to check if title_number of sheets table exists in land_information.
How should I make a query which will result like the expected result below.
Expected Result
id title_number owner case_no
1 001 John 201
3 002 Peter, Andrew 202, 203
Here is my initial sql.
SELECT id,
li.title_number,
owner
FROM sheets AS s
INNER JOIN land_information AS li ON s.title_number = li.title_number;
Well, the query looks like this:
SELECT
MIN(sheets.id) as id,
sheets.title_number as title_number,
GROUP_CONCAT(DISTINCT land_information.owner ORDER BY land_information.id SEPARATOR ',') AS owner,
GROUP_CONCAT(DISTINCT land_information.case_no ORDER BY land_information.id SEPARATOR ',') AS case_no
FROM sheets INNER JOIN land_information ON sheets.title_number = land_information.title_number
GROUP BY (sheets.title_number);
I'll explain one row at a time:
MIN(sheets.id) as id, selects the minimum value from the sheet.id column, inside the group (as it looks inside you expected result)
sheets.title_number as title_number, self explains, it just selects the title number
GROUP_CONCAT(DISTINCT land_information.owner ORDER BY land_information.id SEPARATOR ',') AS owner, groups (enumerates) all land_information.owner, each being added just one time (the DISTINCT keyword), separated by a defined separator
GROUP_CONCAT(DISTINCT land_information.case_no ORDER BY land_information.id SEPARATOR ',') AS case_no same as above, with the case_no column
FROM sheets INNER JOIN land_information ON sheets.title_number = land_information.title_number here we are inner joining both tables, based on the title_number column
GROUP BY (sheets.title_number) all rows having the same title number are joined together, and the coresponding functions defined above are applyed on the group.
The result I've got looks like this
id|title_number|owner |case_no|
--+------------+------------+-------+
1|001 |John |201 |
3|002 |Peter,Andrew|202,203|

ID of the longest string in "group by"

How do I get the id of MAX(name)? The id I get from below query doesn't correspond to the row where MAX(name) is in.
SELECT id, MAX(name) from table group by country
id name country
+---+-----------+---------+
| 1 | John | USA |
+---+-----------+---------+
| 2 | Joe | CHINA |
+---+-----------+---------+
| 3 | Jonah | USA |
+---+-----------+---------+
| 4 | Jonathan | USA |
+---+-----------+---------+
Edit:
The purpose is to get the longest name in every country. So from the table, I'd like to see the result to be id 2 and 4.
You can do it with variables, and self joins, and depending on your version of sql window functions, but you can also do some string manipulation.
SELECT country,
SUBSTRING_INDEX(ids, ',', 1) AS id
FROM (
SELECT country,
GROUP_CONCAT(id ORDER BY LENGTH(NAME) DESC) AS ids
FROM table
GROUP BY country
) z
Also, max(name) won't get you the one with the longest name, it will get you the one closest to the end of the alphabet.
You can also try (assuming you need to account for the possibility of more than one name per country having the same max length):
SELECT z.country, z.id
FROM table z
JOIN (
SELECT country, MAX(LENGTH(name)) AS maxLen
FROM table
GROUP BY country
) lens ON (lens.country = z.country AND lens.maxLen = LENGTH(z.name))
Use a subselect:
SELECT id, country
FROM table
WHERE (country, CHAR_LENGTH(name)) IN (SELECT country, MAX(CHAR_LENGTH(name))
FROM table
GROUP BY country)
GROUP BY country
Note, however, that there may be more than one row returned if there are more than one records having this length of the name!

Group data with id and get data from first and last row

I have a database table schedules, which look like this:
Now, I am trying to get data such as:
----------------------------------------------
| id | bus_id | route | dept_time | arr_time |
----------------------------------------------
| 1 | 1 | 1, 4 | 07:00:59 | 23:30:30 |
----------------------------------------------
route is just the collection of station_id which can be indexed using route_index. When arr_time is NULL, its mean it is the departing station and when dept_time is NULL, its mean, it is the destination. I have group the route with this query:
SELECT id,bus_id,GROUP_CONCAT(station_id SEPARATOR ', ') AS route FROM schedules GROUP BY bus_id;
But I don't know how to get the arr_time and dept_time using this query. Also, how to get station names instead of id in this query. Station table only contains (id and name).
You can use a join to translate station IDs to their names. As for the arrival and departure times - it's a dirty trick, but since aggregate functions ignore nulls, you can use min/max to get them:
SELECT sch.bus_id,
GROUP_CONCAT(st.name ORDER BY route_index SEPARATOR ', ') AS route,
MIN(dept_time) AS dept_time,
MAX(arr_time) AS arr_time
FROM schedules sch
JOIN stations st ON sch.station_id = st.id
GROUP BY bus_id;

SELECT Only Records With Duplicate (Column A || Column B) But Different (Column C) Values

I apologize for the confusing title, I can't figure out the proper wording for this question. Instead, I'll just give you the background info and the goal:
This is in a table where a person may or may not have multiple rows of data, and those rows may contain the same value for the activity_id, or may not. Each row has an auto-incremented ID. The people do not have a unique identifier attached to their names, so we can only use first_name/last_name to identify a person.
I need to be able to find the people that have multiple rows in this table, but only the ones who have multiple rows that contain more than one different activity_id.
Here's a sample of the data we're looking through:
unique_id | first_name | last_name | activity_id
---------------------------------------------------------------
1 | ted | stevens | 544
2 | ted | stevens | 544
3 | ted | stevens | 545
4 | ted | stevens | 546
5 | rachel | jameson | 633
6 | jennifer | tyler | 644
7 | jennifer | tyler | 655
8 | jennifer | tyler | 655
9 | jack | fillion | 544
10 | mallory | taylor | 633
11 | mallory | taylor | 633
From that small sample, here are the records I would want returned:
unique_id | first_name | last_name | activity_id
---------------------------------------------------------------
dontcare | ted | stevens | 544
dontcare | jennifer | tyler | 655
Note that which value of unique_id gets returned is irrelvant, as long as it's one of the unique_ids belonging to that person, and as long as only one record is returned for that person.
Can anyone figure out how to write a query like this? I don't care what version of SQL you use, I can probably translate it into Oracle if it's somehow different.
I would do:
SELECT first_name, last_name, COUNT(DISTINCT activity_id)
FROM <table_name>
GROUP BY first_name, last_name
HAVING COUNT(DISTINCT activity_id) > 0;
I'll build through the logic with you. First, lets find all people that have more than one entry:
Unique list of name + activity ID:
select first_name, last_name,activity_id, count(1)
from yourtable
group by first_name, last_name,activity_id
Now we'll turn that into a subquery and look for users with more than 1 activity_ID
Select first_name, last_name
from
(select first_name, last_name,activity_id, count(1)
from yourtable
group by first_name, last_name,activity_id) a
group by first_name, last_name
having count(1) > 1
Should work as that...I didn't return an activity_id, adding max(activity_id) to the select statement will grab the highest one.
Note that which value of unique_id gets returned is irrelvant, as long as it's one of the unique_ids belonging to that person, and as long as only one record is returned for that person.
These querys should do the trick. there is no need for distinct keywords or an subquery to fetch the results BumbleShrimp needs (if BumbleShrimp needed the correct unique_id also an subquery is needed to match the right value)
Below is the most simple query i could think off that should work, but it could be slow on large tables.
SELECT
first_name
, last_name
, activity_id
FROM
person
GROUP BY
first_name
, last_name
, activity_id
HAVING COUNT(*) >= 2
Could be slow because explain shows "Using index; Using temporary; Using filesort".
Using temporary could trigger an disk based temporary table so we make use off an inner self join to remove the need of an Using temporary.
SELECT
person1.first_name
, person1.last_name
, person1.activity_id
FROM
person person1
INNER JOIN
person person2
ON
person1.unique_id < person2.unique_id
AND
person1.first_name = person2.first_name
AND
person1.last_name = person2.last_name
AND
person1.activity_id = person2.activity_id
ORDER BY
activity_id asc
See demo http://sqlfiddle.com/#!2/fe3ba/29
Side note the inner join will fail if there are three or more duplicates
see demo http://sqlfiddle.com/#!2/1ff33/15
New query
SELECT
first_name
, last_name
, activity_id
FROM
person
GROUP BY
activity_id
, last_name
, first_name
HAVING COUNT(activity_id) >= 2
ORDER BY
activity_id asc
see demo http://sqlfiddle.com/#!2/1e418/3 fixes the three or more duplicates problem / orders activity_id right and can be used on large tables because there is not need off a temporary table what can slow down the execution
To get only the names, the simplest is:
SELECT
first_name
, last_name
FROM
person
GROUP BY
first_name
, last_name
HAVING
COUNT(DISTINCT activity_id) >= 2 ;
To get one row for every name, you can use window function (work fine in Oracle):
WITH cte AS
( SELECT
unique_id, first_name, last_name, activity_id
, COUNT(DISTINCT activity_id) OVER (PARTITION BY last_name, first_name)
AS cnt
, MIN(unique_id) OVER (PARTITION BY last_name, first_name)
AS min_id
FROM
person
)
SELECT
unique_id, first_name, last_name, activity_id
FROM
cte
WHERE
cnt >= 2
AND
min_id = unique_id ;
Instead of MIN(unique_id) OVER ..., you could use MIN(activity_id) OVER ... (or MAX()) and accordingly min_id = activity_id. Or ROW_NUMBER() function. Since you need the COUNT(DISTINCT activity_id) anyway, let me add this version.
With an index on (last_name, first_name, activity_id, unique_id) it should be quite efficient:
WITH cte AS
( SELECT
unique_id, first_name, last_name, activity_id
, COUNT(DISTINCT activity_id) OVER (PARTITION BY last_name, first_name)
AS cnt
, ROW_NUMBER() OVER (PARTITION BY last_name, first_name
ORDER BY activity_id, unique_id)
AS rown
FROM
person
)
SELECT
unique_id, first_name, last_name, activity_id
FROM
cte
WHERE
cnt >= 2
AND
rown = 1 ;
Tested at SQL-Fiddle