How to add an independent column into a query result - sql

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

Related

SQL query combine rows based on common id

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

Many to one merging sql

I have three tables as below:
First Table Second Table Third Table
Name PIN Id City City_id
David 1948 1 Roma 3
Susan 1245 2 Berlin 2
Jack 1578 3 New York 3
Hans 1247 2
Rose 8745 1
I want to merge first and second table according to third table. Result will be: Person
Name PIN City
David 1948 New York
Susan 1245 Berlin
Jack 1578 New York
Hans 1247 Berlin
Rose 8745 Roma
Firsty I can merge second and third table and then merge the result table with first table but I want to solve this problem without a medium table. How can I handle this? How can I combine first table's rows in sequence with a specified row in second table according to third table?
You would need a fourth table, PersonCity, with PersonID and CityID to link together. Think of relational databases like a grid (spreadsheet, roads). If you're going North and the street you want to get on is parallel (think |^| |^|) you're gonna need to use a different road that links the two. Currently, you have no such path.
The short answer is that your tables are not adequate for the task, what you need is along the lines of:
Table_1 Table_2 Table_3
Id Name PIN Id City Name_id City_id
1 David 1948 1 Roma 1 3
2 Susan 1245 2 Berlin 2 2
3 Jack 1578 3 New York 3 3
4 Hans 1247 4 2
5 Rose 8745 5 1
Then you can do your query as follow:
SELECT T1.Name, T1.PIN, T2.City
FROM Table_1 T1 LEFT JOIN Table_3 T2 ON T1.Id = T3.Name_id
LEFT JOIN Table_2 ON T3.City_id = T2.Id
ORDER BY T1.Name
Or you could ORDER BY City, name
I have good news and bad news.
The good news, Given the tables the way they were originally specified, in Oracle, this will give you something that looks like what you are asking:
---
--- Pay attention, This looks right but it is not!
---
select name,pin,city from
( select name,pin,rownum rn from first ) a,
( select city,id from second) b,
( select id,rownum rn from third ) c
where
a.rn=c.rn AND
b.id=c.id;
NAME PIN CITY
-------------------- ---- --------------------
Rose 8745 Roma
Susan 1245 Berlin
Hans 1247 Berlin
David 1948 New York
Jack 1578 New York
The bad news is this does not really work and is cheating. You will get results but they may not be what you would expect and they won't necessarily be consistent.
The database orders records in its own order. If you don't specify an order by clause, you get what they give you, which may not be what you want. This is cheating because Oracle does not REALLY support using rownum in this way because you can't bet on what you will get. This won't work in most other databases.
The only correct way is what #daShier gave, where you have to add something, say, ID, to allow connecting the rows in the order you want.

SQL query to get only rows match the condition based on two separated columns under one 'group by'

The simple SELECT query would return the data as below:
Select ID, User, Country, TimeLogged from Data
ID User Country TimeLogged
1 Samantha SCO 10
1 John UK 5
1 Andrew NZL 15
2 John UK 20
3 Mark UK 10
3 Mark UK 20
3 Steven UK 10
3 Andrew NZL 15
3 Sharon IRL 5
4 Andrew NZL 25
4 Michael AUS 5
5 Jessica USA 30
I would like to return a sum of time logged for each user grouped by ID
But for only ID numbers where both of these values Country = UK and User = Andrew are included within their rows.
So the output in the above example would be
ID User Country TimeLogged
1 John UK 5
1 Andrew NZL 15
3 Mark UK 30
3 Steven UK 10
3 Andrew NZL 15
First you need to identify which IDs you're going to be returning
SELECT ID FROM MyTable WHERE Country='UK'
INTERSECT
SELECT ID FROM MyTable WHERE [User]='Andrew';
and based on that, you can then filter to aggregate the expected rows.
SELECT ID,
[User],
Country,
SUM(Timelogged) as Timelogged
FROM mytable
WHERE (Country='UK' OR [User]='Andrew')
AND ID IN( SELECT ID FROM MyTable WHERE Country='UK'
INTERSECT
SELECT ID FROM MyTable WHERE [User]='Andrew')
GROUP BY ID, [User], country;
So, you have described what you need to write almost perfectly but not quite. Your result table indicates that you want Country = UK OR User = Andrew, rather than AND
You need to select and group by, then include a WHERE:-
Select ID, User, Country, SUM(Timelogged) as Timelogged from mytable
WHERE Country='UK' OR User='Andrew'
Group by ID, user, country

Group columns in query

I have a query where I fetch the following columns:
ID Name Age Hobby
ID, name and age comes from Table A
Hobby comes from Table B
Example of results I can get is the following:
ID Name Age Hobby
0 John 35 Fishing
0 John 35 Tennis
0 John 35 Hiking
1 Jane 31 Fishing
2 Nate 42 Fishing
2 Nate 42 Tennis
What I would like to have as result is the following instead:
ID Name Age Hobby
0 John 35 Fishing, Tennis, Hiking
1 Jane 31 Fishing
2 Nate 42 Fishing, Tennis
Any ideas of how to achieve that?
Try this :
;WITH CTE AS(
SELECT DISTINCT ID,NAME,AGE
FROM TableName
)
SELECT *,
STUFF(SELECT ','+ Hobby FROM TableName t1 WHERE t1.ID=CTE.ID FOR XML PATH(''),1,1,'')
FROM CTE

Limiting records of combinations from 2 columns

looking for some help limiting the results while querying combinations between 2 columns. Here's an example of the kind of table I am working with..
id name group state
1 Bob A NY
2 Jim A NY
3 Dan A NY
4 Mike A FL
5 Tim B NY
6 Sam B FL
7 Brad B FL
8 Glen B FL
9 Ben C FL
I am trying to display all records of all combinations of "group" and "state", but limiting to displaying only up to 2 records for each combination. The result should look like the following..
id name group state
1 Bob A NY
2 Jim A NY
4 Mike A FL
5 Tim B NY
6 Sam B FL
7 Brad B FL
9 Ben C FL
Thanks for the help.
Assuming you always want the two rows for each group and state combination with the lowest id
SELECT *
FROM (SELECT a.*,
row_number() over (partition by group, state
order by id asc) rnk
FROM your_table a)
WHERE rnk <= 2
Of course, since group is a reserved word, I assume your column is actually named something else... You'd need to adjust my query to use the correct column name.