How to combine two columns one below the other in SQLite? - sql

I have a query in SQLite to get all the stations in a train route that, at the end, lets me with two columns named ORI_STATION_ID and ORIG_STATION_ID, like in the image:
This is my current query (ORDER_COL is not shown in the result table, it is only used for ordering):
SELECT table_3.ORI_STATION_ID, table_3.DEST_STATION_ID
FROM table_1
INNER JOIN table_2
ON table_2.ID = table_1.ID
INNER JOIN table_3
ON table_3.ID = table_2.ID
WHERE table_1.CODE = "DINO"
ORDER BY ORDER_COL ASC
I want to get all the stations in the train route, from the first to the last one. Here, the first is the one with ID 1 and the last has ID 19.
I could take the first column and ready to go, but then I would miss the last station. If I took the second column, I would miss the first station.
What I want to do: combine the two columns in one putting one below the other and remove the duplicated stations, so my ALL_STATIONS_COLUMN would look like:
| ALL_STATIONS_COLUMN |
-----------------------
| 1 |
| 2 |
| 9 |
| 10 |
| 11 |
| 19 |
I have seen in other posts how to use joins to combine tables or CONCAT (but seems it doesn't suit for SQLite) but didn't found the proper way.

A union query would be one option here:
SELECT t3.ORI_STATION_ID AS ALL_STATIONS_COLUMN
FROM table_1 t1
INNER JOIN table_2 t2 ON t2.ID = t1.ID
INNER JOIN table_3 t3 ON t3.ID = t2.ID
WHERE t1.CODE = 'DINO'
UNION
SELECT t3.DEST_STATION_ID
FROM table_1 t1
INNER JOIN table_2 t2 ON t2.ID = t1.ID
INNER JOIN table_3 t3 ON t3.ID = t2.ID
WHERE t1.CODE = 'DINO'
ORDER BY ALL_STATIONS_COLUMN;
This kills two birds at the same time (splat), because the union brings together the origin and destination station IDs, while also removing duplicate values should they occur between the two sets.

Sounds like a case for a recursive CTE (Example just uses your final route table; I'm not going to try to come up with three tables worth of data; easy to extend the following with the query that computes that route as another CTE):
WITH cte AS
(SELECT 1 AS all_stations_column, 1 AS stop
UNION
SELECT r.dest_station_id, cte.stop + 1
FROM route AS r
JOIN cte ON r.ori_station_id = cte.all_stations_column)
SELECT all_stations_column FROM cte ORDER BY stop;
giving
all_stations_column
-------------------
1
2
9
10
11
19
dbfiddle example

Related

SQL Subquery Join and Sum

I have Table 1 & 2 with common Column name ID in both.
Table 1 has duplicate entries of rows which I was able to trim using:
SELECT DISTINCT
Table 2 has duplicate numeric entries(dollarspent) for ID's which I needed and was able to sum up:
Table 1 Table 2
------------ ------------------
ID spec ID Dol1 Dol2
54 A 54 1 0
54 A 54 2 1
55 B 55 0 2
56 C 55 3 0
-I need to join these two queries into one so I get a resultant JOIN of Table 1 & Table 2 ON column ID, (a) without duplicates in Table 1 & (b) Summed $ values from Table 2
For eg:
NewTable
----------------------------------------
ID Spec Dol1 Dol2
54 A 3 1
55 B 3 2
Notes : No. of rows in Table 1 and 2 are not the same.
Thanks
Use a derived table to get the distinct values from table1 and simply join to table 2 and use aggregation.
The issue you have is you have a M:M relationship between table1 and table2. You need it to be a 1:M for the summations to be accurate. Thus we derive t1 from table1 by using a select distinct to give us the unique records in the 1:M relationship (assuming specs are same for each ID)
SELECT T1.ID, T1.Spec, Sum(T2.Dol1) as Dol1, sum(T2.Dol2) as Dol2
FROM (SELECT distinct ID, spec
FROM table1) T1
INNER JOIN table2 T2
on t2.ID = T1.ID
GROUP BY T1.ID, T1.Spec
This does assume you only want records that exist in both. Otherwise we may need to use an (LEFT, RIGHT, or FULL) outer join; depending on desired results.
I can't really see your data, but you might want to try:
SELECT DISTINCT ID
FROM TblOne
UNION ALL
SELECT DISTINCT ID, SUM(Dol)
FROM TblTwo
GROUP BY ID
Pre-aggregate table 2 and then join:
select t1.id, t1.spec, t2.dol1, t2.dol2
from (select t2.id, sum(dol1) as dol1, sum(dol2) as dol2
from table2 t2
group by t2.id
) t2 join
(select distinct t1.id, t1.spec
from table1 t1
) t1
on t1.id = t2.id;
For your data examples, you don't need to pre-aggregate table 2. This gives the correct sums -- albeit in multiple rows -- if table1 has multiple specs for a given id.

SQL select 1 to many within the same row

I have a table with 1 record, which then ties back to a secondary table which can contain either no match, 1 match, or 2 matches.
I need to fetch the corresponding records and display them within the same row which would be easy using left join if I just had 1 or no matches to tie back, however, because I can get 2 matches, it produces 2 records.
Example with 1 match:
Select T1.ID, T1.Person1, T2.Owner
From T1
Left Join T2
ON T1.ID = T2.MatchID
Output
ID Person1 Owner1
----------------------
1 John Frank
Example with 2 match:
Select T1.ID, T1.Person1, T2.Owner
From T1
Left Join T2
ON T1.ID = T2.MatchID
Output
ID Person1 Owner
----------------------
1 John Frank
1 John Peter
Is there a way I can formulate my select so that my output would reflect the following When I have 2 matches:
ID Person1 Owner1 Owner2
-------------------------------
1 John Frank Peter
I explored Oracle Pivots a bit, however couldn't find a way to make this work. Also explored the possibility of using left join on the same table twice using MIN() and MAX() when fetching the matches, however I can only see myself resorting this as a "no other option" scenario.
Any suggestions?
** EDIT **
#ughai - Using CTE does address the issue to some extent, however when attempting to retrieve all of the records, the details derived from this common table isn't showing any records on the LEFT JOIN unless I specify the "MatchID" (CASE_MBR_KEY) value, meaning by removing the "where" clause, my outer joins produce no records, even though the CASE_MBR_KEY values are there in the CTE data.
WITH CTE AS
(
SELECT TEMP.BEAS_KEY,
TEMP.CASE_MBR_KEY,
TEMP.FULLNAME,
TEMP.BIRTHDT,
TEMP.LINE1,
TEMP.LINE2,
TEMP.LINE3,
TEMP.CITY,
TEMP.STATE,
TEMP.POSTCD,
ROW_NUMBER()
OVER(ORDER BY TEMP.BEAS_KEY) R
FROM TMP_BEN_ASSIGNEES TEMP
--WHERE TEMP.CASE_MBR_KEY = 4117398
)
The reason for this is because the ROW_NUMBER value, given the amount of records won't necessarily be 1 or 2, so I attempted the following, but getting ORA-01799: a column may not be outer-joined to a subquery
--// BEN ASSIGNEE 1
LEFT JOIN CTE BASS1
ON BASS1.CASE_MBR_KEY = C.CASE_MBR_KEY
AND BASS1.R IN (SELECT min(R) FROM CTE A WHERE A.CASE_MBR_KEY = C.CASE_MBR_KEY)
--// END BA1
--// BEN ASSIGNEE 2
LEFT JOIN CTE BASS2
ON BASS2.CASE_MBR_KEY = C.CASE_MBR_KEY
AND BASS2.R IN (SELECT MAX(R) FROM CTE B WHERE B.CASE_MBR_KEY = C.CASE_MBR_KEY)
--// END BA2
** EDIT 2 **
Fixed the above issue by moving the Row number clause to the "Where" portion of the query instead of within the JOIN clause. Seems to work now.
You can use CTE with ROW_NUMBER() with 2 LEFT JOIN OR with PIVOT like this.
SQL Fiddle
Query with Multiple Left Joins
WITH CTE as
(
SELECT MatchID,Owner,ROW_NUMBER()OVER(ORDER BY Owner) r FROM t2
)
select T1.ID, T1.Person, t2.Owner as Owner1, t3.Owner as Owner2
FROM T1
LEFT JOIN CTE T2
ON T1.ID = T2.MatchID AND T2.r = 1
LEFT JOIN CTE T3
ON T1.id = T3.MatchID AND T3.r = 2;
Query with PIVOT
WITH CTE as
(
SELECT MatchID,Owner,ROW_NUMBER()OVER(ORDER BY Owner) R FROM t2
)
SELECT ID, Person,O1,O2
FROM T1
LEFT JOIN CTE T2
ON T1.ID = T2.MatchID
PIVOT(MAX(Owner) FOR R IN (1 as O1,2 as O2));
Output
ID PERSON OWNER1 OWNER2
1 John Maxwell Peter
If you know there are at most two matches, you can also use aggregation:
Select T1.ID, T1.Person1,
MIN(T2.Owner) as Owner1,
(CASE WHEN MIN(t2.Owner) <> MAX(t2.Owner) THEN MAX(t2.Owner) END) as Owner2
From T1 Left Join
T2
on T1.ID = T2.MatchID
Group By t1.ID, t1.Person1;

Self join for two same rows with one different column

Hi I have table with the following data
A B bid status
10 20 1 SUCCESS_1
10 20 1 SUCCESS_2
10 30 2 SUCCESS_1
10 30 2 SUCCESS_2
Now I want to print or count above rows based on SUCCESS_1 and SUCCESS_2. I created the following query but it does not work it just returns one row by combining two rows.
select * from tbl t1 join tbl t2 on
on (t1.A=t2.A and t1.B=t2.B and
(t1.Status = 'SUCCESS_1' and t2.Status = 'SUCCESS_2')
where t1.bid= 1
I want output as the following for the above query
A B bid status
10 20 1 SUCCESS_1
10 20 1 SUCCESS_2
I am new to SQL please guide. Thanks in advance.
If you need to do the join for some reason (e.g. your database does not let you select everything if you group by 1 column, because it wants everything projected to either be grouped or be an aggregate), you could do the following:
select t1.*
from tbl t1 join tbl t2
on (t1.A=t2.A and t1.B=t2.B and t1.Status = 'SUCCESS_1' and t2.Status = 'SUCCESS_2')
where t1.bid= 1
union all select t2.*
from tbl t1 join tbl t2
on (t1.A=t2.A and t1.B=t2.B and t1.Status = 'SUCCESS_1' and t2.Status = 'SUCCESS_2')
where t1.bid= 1
order by 1,2,3,4
Your original query is pulling back all the data in one row, but this one pulls back the two rows that make that resulting join row separately.
SELECT * FROM `tbl1` WHERE `bid`=1 GROUP BY `status`

SQL Select Query - "Pairing" Records Together

Here's my data:
Table1...
id
field1
field2
...
Table2...
id
table1_original_id
table1_new_id
Table1 holds records that cannot themselves be updated though I built a mechanism for my users to be able to "update" them... they select a record, make changes, and those changes are actually submitted as a new record. For conversation's sake let's assume there are currently 10 records in Table1 with IDs 1 through 10. User submits an update to ID 3. ID 3 remains as it was and a new record, ID 11, is added to Table1. Along with this new record, Table2 gets a new record, with ID = 1, t1_original_id = 3 and t1_new_id = 11.
What would be by SQL select to retrieve the "pairs" of records from Table1... in this case the query would provide me with... IDs 3 and 11.
scratching head
I don't think it matters much by DB platform is Postgres 8.4 and I'm retrieving the data via PHP to be processed in jqGrid. Bonus points if you can point me in the direction of displaying each pair of records in a separate jqGrid!
Thanks for your time and effort.
=== EDIT ===
The following is a sample of what I need returned from the query based on the scenario above:
id field1 field2
3 blah stuff
11 more things
Once I have these pairs back I can process them further, as necessary, on the PHP side.
Standard SQL solution
To get two separate rows (as later specified in the Q update) use a UNION query:
SELECT 'old' AS version, t1.id, t1.field1, t1.field2
FROM table1 t1
JOIN table2 t2 ON t2.table1_original_id = t1.id
WHERE t2.id = $some_t2_id -- your t2.id here!
UNION ALL
SELECT 'new' as version, t1.id, t1.field1, t1.field2
FROM table1 t1
JOIN table2 t2 ON t2.table1_new_id = t1.id
WHERE t2.id = $some_t2_id; -- your t2.id here!
Note: this is one query.
Returns as requested, plus a column version to distinguish the rows reliably:
version | id | field1 | field2
--------+----+--------+--------
old | 3 | blah | stuff
new | 11 | more | things
Faster Postgres-specific solution
A more sophisticated, but shorter and faster solution:
SELECT version, id, field1, field2
FROM (
SELECT unnest(ARRAY['old', 'new']) AS version
,unnest(ARRAY[table1_original_id, table1_new_id]) AS id
FROM table2 t2 WHERE t2.id = $some_t2_id -- your t2.id here!
) t2
JOIN table1 USING (id);
Same result.
-> SQLfiddle demo for both.
You'll need to JOIN to Table1 twice, something like:
SELECT orig.id AS Orig_ID
, orig.value AS Orig_Value
, n.id AS New_ID
, n.value AS New_Value
FROM Table2 a
JOIN Table1 AS orig
ON a.table1_original_id = orig.id
JOIN Table1 AS n
ON a.table1_new_id = n.id
Demo: SQL Fiddle
Update:
To get them paired as you want without manually choosing a set you'll need something like this:
SELECT sub.id,sub.value
FROM (SELECT a.id as Update_ID,o.id,o.value, '1' AS sort
FROM Table2 a
JOIN Table1 AS o
ON a.table1_original_id = o.id
UNION
SELECT a.id as Update_ID, n.id,n.value, '2' AS sort
FROM Table2 a
JOIN Table1 AS n
ON a.table1_new_id = n.id
) AS sub
ORDER BY Update_ID,sort
Demo: Sql Fiddle
Notes: Change UNION to UNION + ALL, can't post those words next to each other due to firewall limitation.
The hard-coded '1' and '2' are so that original always appear before new.

How to have SQL Inner Join to return first entry or blank if no entry

First time posting; been reading alot of answers, and most have helped, but I've gotten stuck on this one. Using Oracle SQL, I'm trying to perform a select with an inner join, but I want to select the first entry from a another table if there is one.
Abbrieviated example:
Table_1
-ID
-Value
1 XYZ
2 ABC
3 DEF
Table_2
-ID
-Value_2
1 Sample_1
3 Sample_2
3 Sample_3
And the result of the select, I am trying to get:
1 XYZ Sample_1
2 ABC ''
3 DEF Sample_2
The select statement I'm using is
SELECT * FROM
(SELECT ID,Value,Value_2 FROM Table_1
INNER JOIN Table_2 ON Table_1.ID = Table_2.ID
WHERE Value_2 = (SELECT MIN(Value_2) FROM Table_2 WHERE ID=Table_2.ID)
);
But the result I'm getting is dropping all the rows where Table_2 doesn't have a match.
1 XYZ Sample_1
3 DEF Sample_2
I tried using COALESCE(), but I'm guessing No Rows Selected isn't the same as NULL. Wish I could use TOP(), but I cannot. Any ideas? Thanks!
Perform a LEFT JOIN against a correlated subquery which returns the MIN(Value_2) per ID. The LEFT JOIN is needed to get blanks absent a match.
SELECT
Table_1.ID,
Table_1.Value,
minval.Value_2
FROM
Table_1
/* Subquery returns least Value_2 per group of ID */
LEFT JOIN (
SELECT ID, MIN(Value_2) AS Value_2 FROM Table_2 GROUP BY ID
) minval ON Table_1.ID = minval.ID
Note, that there really isn't a "first" without an ORDER BY. I have chosen the one that sorts first by Value_2.
http://sqlfiddle.com/#!2/30a6c/5
(Sorry for all the edits - couple of bugfixes in the SQLfiddle)
Could this work for you?
SELECT * FROM
(SELECT ID,Value,Value_2 FROM Table_1
INNER JOIN Table_2 ON Table_1.ID = Table_2.ID
WHERE Value_2 = (SELECT MIN(Value_2) FROM Table_2 WHERE ID=Table_2.ID)
Order by ID Desc limit 0,1
);
Michael's solution is of course correct if you need any other information from Table_2, or need to join other tables (although you can convert my solution to a subselect to work around that). But just to obtain the specific result requested, you can use this simple query:
SELECT Table_1.ID, Table_1.Value, MIN(Table_2.Value_2)
FROM Table_1
LEFT JOIN Table_2 ON Table_1.ID = Table_2.ID
GROUP BY Table_1.ID, Table_1.Value