SQL command to merge rows with common ID? [duplicate] - sql

This question already has an answer here:
Combine values from related rows into a single concatenated string value
(1 answer)
Closed 9 years ago.
I have a table that looks like:
Event ID Name
1 Bob
1 Steve
1 Tom
2 Bob
3 Steve
3 Tom
There are thousands of event IDs, and tens of unique names. I'd like an SQL query to return the following table:
Event ID Names
1 Bob, Steve, Tom
2 Bob
3 Steve, Tom
I'm looking for an aggregate function like SUM() or AVG() except that it joins strings instead of does mathematics.
EDIT: I'm stuck using MS Access on this one.
EDIT 2: I realize that this would be trivial in a client language, but I'm trying to see if I can get an all-SQL solution.

If you are using SQL server you could do something like this
SQL Fiddle Example
WITH x AS
(
SELECT event_id FROM users
GROUP BY event_id
)
SELECT x.event_id,
name = STUFF((SELECT ',' + name
FROM users WHERE event_id = x.event_id
FOR XML PATH('')), 1, 1, '')
FROM x

You don't mention which DBMS you are using but in MySQL it's pretty easy:
SELECT EventId, GROUP_CONCAT(Names)
FROM MyTable
GROUP BY EventId
In SQL Server it's a little trickier. The solution I typically see, requires that you use FOR XML PATH. You can find a good article on how to do this here.

In PostgreSQL this would be:
select EventId, string_agg(name, ',') as names
from the_table
group by EventId;
If you want the names sorted in the list:
select EventId, string_agg(name, ',' order by name) as names
from the_table
group by EventId

Related

SQL: Creating columns based on row data for each user

I have a survey and I want to do aggregations based on the demographic data that come with their responses. However, the survey doesn't automatically format the data for that purpose.
For example, let's say we have a three question survey:
What is your Eye Color? (Demographic Question)
What is your Hair Color? (Demographic Question)
What is your Salary?
The table below is the raw survey data.
UserID
Question
Answer
1
Eye_Color
Brown
1
Hair_Color
Black
1
Salary
$100
2
Eye_Color
Blue
2
Hair_Color
Blond
2
Salary
$150
I want format my data to eventually perform group by's any question that uses "color" . Thus, I need to dynamically create columns on all questions that have "color" in them.
UserID
Question
Answer
Eye_Color
Hair_Color
1
Salary
$100
Brown
Black
2
Salary
$150
Blue
Blond
What SQL query can I use to do this dynamically? I thought about windowing, but I'm sure there is more to it. Also, I am using Google BigQuery for the database.
Thanks!
You might consider below using a dynamic SQL which left-join demographic information to question&answers for each user.
Note that I've added one more question for UserID 1 in your survey data.
CREATE TEMP TABLE responses AS
SELECT 1 UserID, 'Eye_Color' Question, 'Brown' Answer UNION ALL
SELECT 1 UserID, 'Hair_Color' Question, 'Black' Answer UNION ALL
SELECT 1 UserID, 'Salary' Question, '$100' Answer UNION ALL
SELECT 1 UserID, 'Car' Question, 'QM5' Answer UNION ALL
SELECT 2 UserID, 'Eye_Color' Question, 'Blue' Answer UNION ALL
SELECT 2 UserID, 'Hair_Color' Question, 'Blond' Answer UNION ALL
SELECT 2 UserID, 'Salary' Question, '$150' Answer;
EXECUTE IMMEDIATE FORMAT("""
SELECT * FROM (
-- Questions and answers except demographic informations
SELECT * FROM responses WHERE Question NOT LIKE '%%Color%%'
) LEFT JOIN (
-- Demographic informations
SELECT * FROM (
SELECT * FROM responses
) PIVOT (ANY_VALUE(Answer) FOR Question IN ('%s'))
) USING (UserID);
""", (SELECT STRING_AGG(DISTINCT Question, "','") FROM responses WHERE Question LIKE '%Color%'));
Query results
See Also :
EXECUTE IMMEDIATE - https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#execute_immediate
%%Color%% - PARSE_DATE not working in FORMAT() in BigQuery

i want to get all field but without same name in sql

Hi I want to get all field
for example
select * from Stock where MemberId=3430
without same name value but I need Id
select distinct name,id,MemberId where MemberId=3430
Id is unique so distinct is not working correctly for me
Result is like
Id Name
1, Stock1
2, Stock2
3, Stock2
4, Stock1
It doesn't work because id is unique
You didn't specify the flavor of SQL that you're using. I've produced an answer for you that works in Postgres, SQL Server, and MySQL.
To be clear, my understanding of what you're looking for is the ability to return 1 record for "Stock2" with both of the id's associated with that value, rather than 2 separate records. To do this you need some sort of string aggregation capability. Here are three examples that will produce results you are looking for:
Postgres - dbfiddle link - https://www.db-fiddle.com/f/cWoFG13QYyi52Vww5HxoDi/1
SELECT array_agg(id), name
from sample
group by name;
SELECT array_to_string(array_agg(id), ','), name
from sample
group by name
MySQL
SELECT group_concat(id), name
from sample
group by name
SQL Server - sqlfiddle link - http://sqlfiddle.com/#!18/111ba7/4/0
SELECT string_agg(id, ','), name
from sample
group by name;

Merge Data from one Table into a new one in SQL Server [duplicate]

This question already has answers here:
How to concatenate text from multiple rows into a single text string in SQL Server
(47 answers)
Closed 1 year ago.
I am encountering a problem with joining a table in SQL Server. I get more rows than I need in my view.
The table I join looks something like this:
ID
other ID
Name
1
1
Bob
2
1
Max
3
2
Jim
4
2
Tom
5
2
Ron
The new table should look like this:
other ID
Names
1
Bob,Max
2
Jim,Tom,Ron
In that way I don’t get a new row every time a new Name comes up, but it's the same "other" ID.
Can someone please help me solve this problem? Thank you.
If your DBMS is SQL Server(2017+) or Postgres, you can use STRING_AGG aggregate function to have the names that are associated to the same id in a one row. Here is an exmple
SELECT other_id,
STRING_AGG(Name, ',')
FROM table_name
GROUP BY other_id
ORDER BY other_id
You basically have to use a group by with some string aggregate functions
Select id, string_agg(name, ',' ) from table1
t1 Join table2 t2 on t1.id=t2.id group by id

Node / Postgres SQL Select distinct entries then put all other entries with the same reference into one column

this question was probably asked somewhere but I can't seem to phrase it correctly in the search to find an accurate answer.
I'm doing a query on a Postgres DB, it has quite a few joins, the results are something like this:
WON | name | item
1 Joe A
1 Joe B
2 Smith A
So one row for each entry, I need to somehow get the result back as such:
WON | name | item
1 Joe A, B
2 Smith A
This can be done in the query or with NodeJS, there are hundreds to thousands of results for the query, so getting a distinct row (WON 1) then searching the DB for all entries that match it then repeating for the rest isn't feasible, so this may be better done in Node / Javascript, but I'm somewhat new to that, what would be a (somewhat) efficient way to do this?
If there IS a way to do this in the query itself then that would be my preference though.
Thanks
A sql approach:
SELECT won, name
,STRING_AGG(item, ',' ORDER BY item) AS items
FROM myTable
GROUP BY won, name
ORDER BY won, name
You can use GROUP BY and string_agg to cancat rows, somelike this:
Create table:
CREATE TABLE test
(
won int,
name character varying(255),
item character varying(255)
);
insert into test (won, name, item) values (1,'Joe', 'A'),(1, 'Joe', 'B'),(2, 'Smith', 'A')
And do this in the query:
select won, name, string_agg(item, ',') from test group by won, name order by won
See this example in sqlFiddle

Building a hierarchical tree with a single SQL query

I have a SQL table with the following structure.
id - int
par - int (relational to id)
name - varchar
Column par contains references to id or NULL if no reference, this table is meant to build an hierarchical tree.
Then, given the data:
id par name
1 NULL John
2 NULL Mario
3 1 George
4 3 Alfred
5 4 Nicole
6 2 Margaret
I want to retrieve a hierarchical tree, up to the last parent, from a given single id.
Example, I want to know the tree from Nicole to the last parent. So the query result will be:
id par name
5 4 Nicole
4 3 Alfred
3 1 George
1 NULL John
I would normally do this with a SQL query repeating over and over and building the tree server side but I do not want that now.
Is there any way to achieve this with a single SQL query?
I need this for either MySQL or PgSQL.
And I want to know also, if possible, is it also widely supported? In which versions of either MySQL or PgSQL can I expect support?
It is possible with a single query in Postgres using a recursive common table expression. This is not possible in MySQL as it is one of the few database to not support recursive CTEs.
It would look something like this (not tested)
WITH RECURSIVE tree (id, par, name) AS (
SELECT id, par, name
FROM the_table
WHERE name = 'Nicole'
UNION ALL
SELECT id, par, name
FROM the_table tt
JOIN tree tr ON tr.id = tt.par
)
SELECT *
FROM tree
For Postgres, see http://www.postgresql.org/docs/8.4/static/queries-with.html
MySQL doesn't support this syntax (unless it's in a beta/development tree somewhere). Oracle has something similar using connect by prior.
This article is probably what you need to look at:
http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/
In Oracle, this is done via:
SELECT [[LEVEL,]] id, par, name FROM my_table
START WITH name = 'Nicole'
CONNECT BY [[NOCYCLE]] id = PRIOR par
[[ORDER SIBLINGS BY name ASC]]
(my [[…]] syntax denotes optional query bits.
MySQL is planning to integrate such a feature. For PostgreSQL there is another answer helping you.