SQL query combine rows based on common id - sql

I have a table with the below structure:
MID
FromCountry
FromState
FromCity
FromAddress
FromNumber
FromApartment
ToCountry
ToCity
ToAddress
ToNumber
ToApartment
123
USA
Texas
Houston
Well Street
1
Japan
Tokyo
6
ET3
123
Germany
Bremen
Bremen
Nice Street
4
Poland
Warsaw
9
ET67
456
France
Corsica
Corsica
Amz Street
3
Italy
Milan
8
AEC784
456
UK
UK
London
G Street
2
Portugal
Lisbon
1
LP400
The desired outcome is:
MID
FromCountry
FromState
FromCity
FromAddress
FromNumber
FromApartment
ToCountry
ToCity
ToAddress
ToNumber
ToApartment
FromCountry1
FromState1
FromCity1
FromAddress1
FromNumber1
FromApartment1
ToCountry1
ToCity1
ToAddress1
ToNumber1
ToApartment1
123
USA
Texas
Houston
Well Street
1
Japan
Tokyo
6
ET3
Germany
Bremen
Bremen
Nice Street
4
Poland
Warsaw
9
ET67
456
France
Corsica
Corsica
Amz Street
3
Italy
Milan
8
AEC784
UK
UK
London
G Street
2
Portugal
Lisbon
1
LP400
What I am trying to achieve is to bring multiple rows in 1 table, which have the same MID, under 1 row, regardless if there are columns with empty values.
I think that i over complicated the solution to this as I was trying something like this (and of course the outcome is not the desired one):
select [MID],
STUFF(
(select concat('', [FromCountry])
FROM test i
where i.[MID] = o.[MID]
for xml path ('')),1,1,'') as FromCountry
,stuff (
(select concat('', [FromState])
FROM test i
where i.[MID] = o.[MID]
for xml path ('')),1,1,'') as FromState
,stuff (
(select concat('', [FromCity])
FROM test i
where i.[MID] = o.[MID]
for xml path ('')),1,1,'') as FromCity
,stuff (
(select concat('', [FromAddress])
FROM test i
where i.[MID] = o.[MID]
for xml path ('')),1,1,'') as FromAddress
FROM test o
group by [MID]
...
Is there any way to achieve this?

On the assumption there are no more than 2 rows per MID then you can implement a simple row_number() solution.
You need to join one row for each MID to the other, so assign a unique value to each using row_number - there's nothing I can immediately see that indicates which row should be the "second" row - this is assigning row numbers based on the FromCountry - amend as necessary.
I'm not reproducing all the columns here but you get the idea, rinse and repeat for each column.
with m as (
select *, Row_Number() over(partition by Mid order by FromCountry) seq
from t
)
select m.Mid,
m.fromcountry, m.fromstate,
m2.fromcountry FromCountry1, m2.fromstate FromState1
from m
join m m2 on m.mid = m2.mid and m2.seq = 2
where m.seq = 1;
See example fiddle

Related

SQL Combine duplicate rows while concatenating one column

I have a table (example) of orders show below. The orders are coming in with multiple rows that are duplicated for all columns except for the product name. We want to combine the product name into a comma delimited string with double quotes. I would like to create a select query to return the output format shown below.
INPUT
Name address city zip product name
-----------------------------------------------------------------
John Smith 123 e Test Drive Phoenix 85045 Eureka Copper Canyon, LX 4-Person Tent
John Smith 123 e Test Drive Phoenix 85045 The North Face Sequoia 4 Tent with Footprint
Tom Test 567 n desert lane Tempe 86081 Cannondale Trail 5 Bike - 2021
OUTPUT
Name address city zip product name
------------------------------------------------------------------
John Smith 123 e Test Drive Phoenix 85045 "Eureka Copper Canyon, LX 4-Person Tent", "The
North Face Sequoia 4 Tent with Footprint"
Tom Test 567 n desert lane Tempe 86081 Cannondale Trail 5 Bike - 2021
You can have List_AGG() OR GROUP_CONCAT and then join the results back to original table. Then you can remove duplicates using row_number which will create a same rank
if data is same
WITH ALL_DATA AS (
SELECT * FROM TABLE
),
LIST_OF_ITEMS_PER_PRODUCT AS (
SELECT
ALL_DATA.NAME,
LIST_AGG(ALL_DATA.PRODUCT_NAME , ",") AS ALL_PRODUCTS_PER_PERSON
-- IF YOUR SQL DON'T SUPPORT LIST_AGG() THEN USE GROUP_CONCAT INSTEAD
FROM
ALL_DATA
GROUP BY 1
),
LIST_ADDED AS (
SELECT
ALL_DATA.*,
LIST_OF_ITEMS_PER_PRODUCT.ALL_PRODUCTS_PER_PERSON
FROM
ALL_DATA
LEFT JOIN LIST_OF_ITEMS_PER_PRODUCT
ON ALL_DATA.NAME = LIST_OF_ITEMS_PER_PRODUCT.NAME
),
ADDING_ROW_NUMBER AS (
SELECT
* ,
ROW_NUMBER() over (partition by list_added.NAME, ADDRESS, CITY, ZIP ORDER BY NAME) AS ROW_NUMBER_
FROM LIST_ADDED
)
SELECT
* FROM
ADDING_ROW_NUMBER
WHERE ROW_NUMBER_ = 1

How group by count from multiple tables

I have 3 different tables, country, city, and customer. Tables are shown below:
country table:
id country_name
1 UK
2 US
3 Brazil
:
n Canada
city table
id city_name postal_code country_id
1 London 30090 1
2 Dallas 20909 2
3 Rio 29090 3
4 Atlanta 30318 2
:
n Vancouver 32230 n
customer table
id customer_name city_id
1 John 1
2 Pete 3
3 Dave 2
4 May 2
5 Chuck 4
6 Sam 3
7 Henry 3
***country.id is references city.country_id, and city.id is references customer.city_id
I want to write a query that can extract the country name, city name and the count of the customer of the associate city. But with one condition, the query will return all cities with more customers than the average number of customers of all cities
It will look something like below, this is the correct output
UK London 2
Brazil Rio 3
but I kept getting this output, which isn't correct
UK London 2
US Dallas 2
US Atlanta 1
Brazil Rio 3
I fixed my SQL query but it doesn't give me the result that I want
SELECT country.country_name, city.city_name, COUNT(customer.city_id) from country
JOIN city on country.id = city.country_id
JOIN customer on city.id = customer.city_id
Group by city_name,country.country_name;
I am wondering how can I do this and fix my code?
add country.country_name in group by
SELECT country.country_name, city.city_name, COUNT(customer.city_id) from country
JOIN city on country.id = city.country_id
JOIN customer on city.id = customer.city_id
Group by city_name,country.country_name
You are missing country.country_name in the query it will give you error. As a general rule all columns on which aggregate function is not applied should be part of group by clause.
So either you write your query without country_name in the select or add country_name in the group by clause.

Check for an entry in SQL Server

-----------------------
country | city | ids
-----------------------
India Mumbai 1
India Chennai 2
India Kolkata 3
---------------------
USA New York 2
USA Utah 3
---------------------
I have given a sample from a table. From the table, I am trying to query all the countries without id 1. I wrote this(Country was not included in the Where condition since it needs to apply to all the countries of the table).
Select * from Countries
WHERE id<>1
I got this.
-----------------------
country | city | ids
-----------------------
India Chennai 2
India Kolkata 3
---------------------
USA New York 2
USA Utah 3
---------------------
But I need the output to contain only USA(which does not have id=1). Is there any workaround for this?
SELECT * from Countries WHERE country not in
(SELECT country from Countries WHERE id=1)
use NOT EXISTS
Select *
from Countries c
where not exists
(
select *
from Countries x
where x.country = c.country
and x.id = 1
)
You need to group by Country like below :
SELECT C.Country
FROM City
WHERE C.Country NOT IN
(SELECT country FROM City WHERE id=1)
SQL Fiddle Demo
OR
SELECT
C.Country
FROM
City C
GROUP BY C.Country
HAVING C.Country NOT IN
(
SELECT Country FROM City WHERE Id =1
)
SQL Fiddle Demo

How to add an independent column into a query result

I try to googling for this issue and still couldn't find the solution.
I have 2 column to combine like below:
First table:
ID Name Item
42 america 1433
42 america 1695
42 america 1234
8 london 1433
8 london 1705
8 london 1432
Second table:
ID CreatedBy
42 John
42 Erica
8 Amy Song
8 Alfred
If I just join both table it will become like this:
ID Name Item CreatedBy
42 america 1433 John
42 america 1695 John
42 america 1234 John
42 america 1433 Erica
42 america 1695 Erica
42 america 1234 Erica
8 london 1433 Amy Song
8 london 1705 Amy Song
8 london 1432 Amy Song
8 london 1433 Alfred
8 london 1705 Alfred
8 london 1432 Alfred
Column Created By is only related to ID, and not related to Name and Item.
I just want to insert CreatedBy as a new column into first table that only linked to ID, so the expected result will be like below.
Is there any way I could get result like this?
ID Name Item CreatedBy
42 america 1433 John
42 america 1695 Erica
42 america 1234 NULL
8 london 1433 Amy Song
8 london 1705 Alfred
8 london 1432 NULL
Let say we change second table like this:
Second table:
ID CreatedBy
42 John
8 Amy Song
Result will be like this:
ID Name Item CreatedBy
42 america 1433 John
42 america 1695 NULL
42 america 1234 NULL
8 london 1433 Amy Song
8 london 1705 NULL
8 london 1432 NULL
I really apreacite for your help, and thank you in advanced masta.
NOTE: Column CreatedBy is the independent column that only relate to ID and not relate to Name and Item.
So, I will answer you even though some guys that discussed it here on comments may disagree as there is no a proper logic to your problem.
It is important to note that this answer is for this SPECIFIC case if it won't get you the right data for a larger dataset you have to provide more info on it.
What I did:
I've created a subset from the first set ordering it (and indexing it, window function) by the name then I created another subset from the second set ordering it by the id so, i have:
select id, name, item, row_number() over (partition by name order by name) idx from tablea
And
select id, createdby, row_number() over (partition by id order by id) idx from tableb
Then I LEFT JOIN the tablea with tableb by the id and the order created colum idx so
select a.id, a.name, a.item, b.createdby
from (select id, name, item, row_number() over (partition by name order by name) idx from tablea) a
left join
(select id, createdby, row_number() over (partition by id order by id) idx from tableb) b
on (a.id = b.id and a.idx=b.idx)
order by a.name
The order by is just to get the result as you asked on your question.
See it here: http://sqlfiddle.com/#!3/7ef70/3
For your second sample data: http://sqlfiddle.com/#!3/675625/1

How to do Conditional Column Joins in SQL?

I have a tables below
Main Table: tblMain
Phase Country City
AAA India Bangalore
AAA USA Chicago
ZZZ USA
ZZZ UK
SubTable: tblSub
Phase Country City Value
AAA USA Chicago 3
AAA USA NY 6
AAA UK London 5
AAA India Bangalore 6
AAA India Delhi 9
ZZZ USA Chicago 7
ZZZ UK London 8
Expected Result
Phase Country City Value
AAA India Bangalore 6
AAA USA Chicago 3
ZZZ USA 7
ZZZ UK 8
I want to join this with my Main table which has Phase, Country and City, however the condition is
For Phase "ZZZ" i want to join only by Country where as for Phase "AAA" i want to join ty Country & City. Is is possible to do in SQL Query without a Stored procedure or temp tables
I am looking to achieve this in plain query. Thanks in advance!!!
SELECT *
FROM This_Table TT
LEFT JOIN Main_Table MT ON TT.Countrry = MT.Country
AND TT.Phase = 'ZZZ'
LEFT JOIN Main_Table MT2 ON TT.Countrry = MT2.Country
AND TT.City = MT2.City
AND TT.Phase = 'AAA'
This should do it:
WHERE
(a.phase = 'ZZZ' AND a.country = b.country)
OR
(a.phase = 'AAA' AND a.country = b.country AND a.city = b.city)