This question already has answers here:
GROUP_CONCAT in SQLite
(2 answers)
Closed 15 days ago.
I have the results from a select statement as seen below:
+-----------+-------------------------+
| city | category |
+-----------+-------------------------+
| Aurora | Indian |
| Aurora | Pakistani |
| Aurora | Restaurants |
| Avondale | Health & Medical |
| Avondale | Optometrists |
| Brampton | Beauty & Spas |
| Brampton | Hair Salons |
| Brampton | Indian |
| Brampton | Nail Salons |
+-----------+-------------------------+
I want to try group the results to something like this:
+-----------+-------------------------------------------------+
| city | category |
+-----------+-------------------------------------------------+
| Aurora | Indian, Pakistani, Restaurants |
| Avondale | Health & Medical, Optometrists |
| Brampton | Beauty & Spas, Hair Salons, Indian, Nail Salons |
+-----------+-------------------------------------------------+
The code I used to extract the initial columns results was this SQL query:
SELECT B.City, C.Category
FROM Business B
INNER JOIN Category C
ON B.id = C.business_id
Any help would be appreciated, thank you
Thanks to The Impaler I referenced the SQLite documentation and used GROUP_CONCAT to combine the results for all the categories in their subsequent cities with the following query:
SELECT B.City As City, GROUP_CONCAT(C.Category, ', ') As Category
FROM Business B
INNER JOIN Category C
ON B.id = C.business_id
GROUP BY B.City
I think that you should use
GROUP_CONCAT
SELECT B.City, GROUP_CONCAT(C.Category SEPARATOR ', ') as category
FROM Business B
INNER JOIN Category C
ON B.id = C.business_id
GROUP BY B.City;
I hope this helps!
You can do it by group by as:
DECLARE #Names varchar(1000)
Select City, #Names = #Names + ', ' + Category from B Group by City
Related
I use SQL Server 2017 and have a simple query with joins that looks like this.
SELECT DISTINCT
[p].[MainTitle] AS Title,
[pe].[Name] AS JobName,
[ea].[Label] AS Stat
FROM
[Project] AS [P]
INNER JOIN
[ProjectExtended] AS [pe] ON [p].[ID] = [pe].[ProjectID]
INNER JOIN
[ExtAttributes] AS [ea] ON [pe].[AttributeID] = [ea].[ID]
...
WHERE
pe.date BETWEEN #start AND #end
AND [ea].Label IN ('A', 'B', 'C')
The result right know looks like this (JobName is different for every Title but always the same for the same Title)
+-----------+----------+--------------+
| Title | JobName | Stat |
+-----------+----------+--------------+
| BAMB | asdf | C |
| BIRT | fdsa | B |
| BIRT | fdsa | A |
| BOND | lofe | B |
+-----------+----------+--------------+
But I want it to show like this.
+-----------+----------+--------------+
| Title | JobName | Stat |
+-----------+----------+--------------+
| BAMB | asdf | C |
| BIRT | fdsa | B, A |
| BOND | lofe | B |
+-----------+----------+--------------+
I tried with different versions of CONCAT, STRING_AGG functions that you suggested in different threads, but no success. I only got to the point where it joins all the stats in last column - result was like A, B, C in every row.
This should help:
SELECT
[t].[Title] AS Title,
[t].[JobName] AS JobName,
STRING_AGG([t].[Stat], ',') AS Stat
FROM (
SELECT DISTINCT
[p].[MainTitle] AS Title,
[pe].[Name] AS JobName,
[ea].[Label] AS Stat
FROM
[Project] AS [P]
INNER JOIN
[ProjectExtended] AS [pe] ON [p].[ID] = [pe].[ProjectID]
FULL OUTER JOIN
[ExtAttributes] AS [ea] ON [pe].[AttributeID] = [ea].[ID]
...
WHERE
pe.date BETWEEN #start AND #end
AND [ea].Label IN ('A', 'B', 'C', NULL)
) t
GROUP BY
[t].[Title]
, [t].[JobName]
It says version 15 but hopefully is available on yours also
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15
I'm trying to use the SQL join function to grab information from multiple tables.
My issue is I can't seem to get the desired result.
select a.DRINKER, sum(C.PRICE)
from DRINKERS a
left join ORDERS b on a.DRINKER = b.DRINKER
join SERVES c on b.PUB = c.PUB and d.DRINK = c.DRINK
group by a.DRINKER;
This gives the following results
----------------------
|DRINKER|sum(C.PRICE)|
----------------------
| BOB | 200.10 |
| NED | 172.50 |
| JOE | 270.90 |
| TIM | 80.10 |
----------------------
However I want this to be giving all of the people in a.DRINKER like such:
----------------------
|DRINKER|sum(C.PRICE)|
----------------------
| BOB | 200.10 |
| NED | 172.50 |
| JOE | 270.90 |
| TIM | 80.10 |
| PAT | null |
| ANN | null |
----------------------
Any guidance would be appreciated and if you could also explain the logic behind the changes that would be greatly appreciated as I wanna learn what I should be doing! Thanks in advance!
Even though you got a left join between DRINKERS and ORDERS, the join between ORDERS and SERVES, will filter out any nulls obtained in the first left join.
To fix this you could try by further left joining the tables
select a.DRINKER, sum(C.PRICE)
from DRINKERS a
left join ORDERS b on a.DRINKER = b.DRINKER
left join SERVES c on b.PUB = c.PUB and d.DRINK = c.DRINK
group by a.DRINKER;
I'm struggling with getting data from 7 different sql-tables without receiving too many rows.
I have the following (simple) query which retrieves data from 7 different tables:
SELECT h.name, h.address, h.zipcode, h.city, h.association, r.name_de, f.first_name, f.last_name, f.email, p.year, j.name
FROM `tx_gipdhotels_domain_model_hotel` AS h
JOIN `tx_gipdhotels_hotel_jobs_mm` AS hj ON h.uid = hj.uid_local
JOIN `tx_gipdhotels_domain_model_jobs` AS j ON j.uid = hj.uid_foreign
JOIN `tx_gipdhotels_hotel_participations_mm` AS hp ON h.uid = hp.uid_local
JOIN `tx_gipdhotels_domain_model_participations` AS p ON p.uid = hp.uid_foreign
JOIN `tx_gipdhotels_domain_model_region` AS r ON r.uid = h.region
JOIN `fe_users` AS f ON f.uid = h.feuser
As you can see there are two many-to-many-relationships between the tables. These two tables aren't related (except through the h table). Now the problem is that this results in receiving a row for each possible combination of these mm-tables.
Example:
table 1 hotel
|-----------|------------|----------|----------|
| uid | name | jobs | part |
|...........|............|..........|..........|
| 1 | ab | 3 | 2 |
| | | | |
table 2 jobs
|-----------|------------|
| uid | name |
|...........|............|
| 1 | tech |
| 2 | cs |
| 3 | perf |
| | |
table 3 part
|-----------|------------|
| uid | name |
|...........|............|
| 1 | abcd |
| 2 | efgh |
| | |
With this combination (including mm-tables for hotel_jobs and hotel_part) I would receive 6 rows for one hotel only and in each row only one value would differ from another row:
result:
|-----------|------------|----------|----------|
| uid | name | job | part |
|...........|............|..........|..........|
| 1 | ab | tech | abcd |
| 1 | ab | tech | defg |
| 1 | ab | cs | abcd |
| 1 | ab | cs | defg |
| 1 | ab | perf | abcd |
| 1 | ab | perf | defg |
| | | | |
It would be lovely if I could retrieve this data in one single row like the following:
wanted result:
|-----------|------------|--------------------|----------------|
| uid | name | job | part |
|...........|............|....................|................|
| 1 | ab | tech, cs, perf | abcd, efgh |
| | | | |
I can't figure out how to get the wanted result, it exceeds my experience and knowledge so I'm asking you, do you know how to achieve this with a single query?
I've googled quite a bit and I have found the STUFF() method but it's not supported in MariaDB. In some question here on stack someone has done something similar with a cast but I didn't understand it too well and I didn't know how to adapt this to my problem...
I'm using MariaDB and the query will be made from php. There is no way of changing the data structure of the tables.
Any help and explanations would be greatly appreciated.
I hope this will work, try it, if there is any error, we are gonna fix it.
SELECT
h.name,
h.address,
h.zipcode,
h.city,
h.association,
GROUP_CONCAT(DISTINCT p.year SEPARATOR ', '),
GROUP_CONCAT(DISTINCT j.name SEPARATOR ', '),
r.name_de,
f.first_name,
f.last_name,
f.email,
h.tstamp,
h.crdate
FROM tx_gipleasedisturbhotels_domain_model_hotel AS h
JOIN `tx_gipleasedisturbhotels_hotel_jobs_mm` AS hj
ON h.uid = hj.uid_local
JOIN `tx_gipleasedisturbhotels_domain_model_jobs` AS j
ON j.uid = hj.uid_foreign
JOIN `tx_gipleasedisturbhotels_hotel_participations_mm` AS hp
ON h.uid = hp.uid_local
JOIN `tx_gipleasedisturbhotels_domain_model_participations` AS p
ON p.uid = hp.uid_foreign
JOIN `tx_gipleasedisturbhotels_domain_model_region` AS r
ON r.uid = h.region
JOIN `fe_users` AS f
ON f.uid = h.feuser
GROUP BY h.name
ORDER BY h.name ASC
Thanks to #jarlh I found the solution:
SELECT h.name, h.address, h.zipcode, h.city, h.association,
GROUP_CONCAT(DISTINCT p.year SEPARATOR ', '),
GROUP_CONCAT(DISTINCT j.name SEPARATOR ', '),
r.name_de, f.first_name, f.last_name, f.email, h.tstamp, h.crdate
FROM `tx_gipleasedisturbhotels_domain_model_hotel` AS h
JOIN `tx_gipleasedisturbhotels_hotel_jobs_mm` AS hj ON h.uid = hj.uid_local
JOIN `tx_gipleasedisturbhotels_domain_model_jobs` AS j ON j.uid = hj.uid_foreign
JOIN `tx_gipleasedisturbhotels_hotel_participations_mm` AS hp ON h.uid = hp.uid_local
JOIN `tx_gipleasedisturbhotels_domain_model_participations` AS p ON p.uid = hp.uid_foreign
JOIN `tx_gipleasedisturbhotels_domain_model_region` AS r ON r.uid = h.region
JOIN `fe_users` AS f ON f.uid = h.feuser
GROUP BY h.name
ORDER BY h.name ASC
It's a combination of GROUP_CONCAT and GROUP BY. It has to be grouped by the field which you want to have only once. To get all mm-values to one single cell you'll have to use GROUP_CONCAT on those fields in the SELECT statement.
With this query I receive the wanted result. Maybe this will be helpful to someone else as well. ;)
Here are the two tables i have: [all columns in both tables are of type "text"], Table name and the column names are in bold fonts.
Names
--------------------------------
Name | DoB | Team |
--------------------------------
Harry | 3/12/85 | England
Kevin | 8/07/86 | England
James | 5/05/89 | England
Scores
------------------------
ScoreName | Score
------------------------
James-1 | 120
Harry-1 | 30
Harry-2 | 40
James-2 | 56
End result i need is a table that has the following
NameScores
---------------------------------------------
Name | DoB | Team | ScoreData
---------------------------------------------
Harry | 3/12/85 | England | "{"ScoreName":"Harry-1", "Score":"30"}, {"ScoreName":"Harry-2", "Score":"40"}"
Kevin | 8/07/86 | England | null
James | 5/05/89 | England | "{"ScoreName":"James-1", "Score":"120"}, {"ScoreName":"James-2", "Score":"56"}"
I need to do this using a single SQL command which i will use to create a materialized view.
I have gotten as far as realising that it will involve a combination of string_agg, JOIN and JSON, but haven't been able to crack it fully. Please help :)
I don't think the join is tricky. The complication is building the JSON object:
select n.name, n.dob, n.team,
json_agg(json_build_object('ScoreName', s.name,
'Score', s.score)) as ScoreData
from names n left join
scores s
ons.name like concat(s.name, '-', '%')
group by n.name, n.dob, n.team;
Note: json_build_object() was introduced in Postgres 9.4.
EDIT:
I think you can add a case statement to get the simple NULL:
(case when s.name is null then NULL
else json_agg(json_build_object('ScoreName', s.name,
'Score', s.score))
end) as ScoreData
Use json_agg() with row_to_json() to aggregate scores data into a json value:
select n.*, json_agg(row_to_json(s)) "ScoreData"
from "Names" n
left join "Scores" s
on n."Name" = regexp_replace(s."ScoreName", '(.*)-.*', '\1')
group by 1, 2, 3;
Name | DoB | Team | ScoreData
-------+---------+---------+---------------------------------------------------------------------------
Harry | 3/12/85 | England | [{"ScoreName":"Harry-1","Score":30}, {"ScoreName":"Harry-2","Score":40}]
James | 5/05/89 | England | [{"ScoreName":"James-1","Score":120}, {"ScoreName":"James-2","Score":56}]
Kevin | 8/07/86 | England | [null]
(3 rows)
I have the following Table. What I want to get is the missing combinations of Student, Class, Book. I have a query below that does it, but I would like others to provide more efficient queries (ie possibly ones that use group by) to find the missing combos.
SQL FIDDLE HERE - http://sqlfiddle.com/#!6/16e2b/3
StudentBook Table
+---------+---------+--------------+
| Student | Class | Book |
+---------+---------+--------------+
| Albert | Math | AlgebraBook |
| Albert | Math | FractionBook |
| Bridget | Math | AlgebraBook |
| Bridget | Math | FractionBook |
| Charles | Math | AlgebraBook |
| Charles | Math | FractionBook |
| Debbie | English | NovelBook |
| Debbie | English | PoemBook |
| Edward | English | PoemBook |
| Frank | English | PoemBook |
+---------+---------+--------------+
The following Rows in the Set are the missing combinations
Correct Result of My Query Below
+---------+---------+-----------+
| Student | Class | Book |
+---------+---------+-----------+
| Edward | English | NovelBook |
| Frank | English | NovelBook |
+---------+---------+-----------+
And I can use the following Query to get the Missing Combinations, but I want a faster more efficient solutions. Basically I'm looking for other more Effective Techniques, such as possibly using Group By.
WITH CTE_ClassBooks AS
(
SELECT DISTINCT Class, Book FROM StudentBook
),
CTE_StudentClasses AS
(
SELECT DISTINCT Student, Class FROM StudentBook
),
CTE_CombosOfStudentClassBooks AS
(
SELECT DISTINCT b.Student, a.Class, a.Book
FROM CTE_ClassBooks a
INNER JOIN CTE_StudentClasses b ON a.Class = B.Class
)
SELECT * FROM CTE_CombosOfStudentClassBooks
EXCEPT
SELECT * FROM StudentBook
This might be a little faster, your route doesn't seem terribly inefficient though.
;WITH cte AS (SELECT DISTINCT Class,Book FROM Table1)
SELECT b.Student,a.*
FROM cte a
JOIN Table1 b
ON a.Class = b.Class
LEFT JOIN Table1 c
ON a.Class = c.CLass
AND a.Book = c.Book
AND b.Student = c.Student
WHERE c.Class IS NULL
Demo: SQL Fiddle
SELECT S1.STUDENT,S1.CLASS,S2.BOOK FROM
STUDENTBOOK S1,(SELECT DISTINCT CLASS,BOOK FROM STUDENTBOOK) S2
WHERE S1.CLASS = S2.CLASS
AND S1.BOOK <> S2.BOOK
EXCEPT
SELECT STUDENT,CLASS,BOOK FROM STUDENTBOOK