Oracle SQL: Merge select results on top of each other - sql

Lets say you have two queries. Query A results in:
| A | B | C |
+---+---+---+
| 1 | 5 | 9 |
| 2 | 6 | 10|
And Query B results in:
| A | B | C |
+---+---+---+
| 3 | 7 | 11|
| 4 | 8 | 12|
Is it possible to execute the statements in a way to get:
| A | B | C |
+---+---+---+
| 1 | 5 | 9 |
| 2 | 6 | 10|
| 3 | 7 | 11|
| 4 | 8 | 12|
Would the simpler solution be to join them? Or if it involves using ';' to separate the two selects I'm getting an error using it.
Also, I have tried using UNION or UNION ALL between the statements but that gives
ORA-00933: SQL command not properly ended
This is being done in Excel's Microsoft query.

Use a UNION statement.
SELECT * FROM queryA
UNION ALL
SELECT * FROM queryB
The WHERE clauses stay with each query, but the ORDER BY moves to the very end.
When you use UNIONs, the name or alias of the column in the top most query becomes the alias for the entire column. So at the end, you would just write something like Order By A where A is your first column name. Make sure you don't have aliases specified in queries other than the top most one.

Related

Can't figure out sql join

I'm using nextcloud to track data via the forms app, the table oc_forms_v2_submissions contains the entries:
SELECT * FROM `oc_forms_v2_submissions` WHERE `form_id` = 3;
+----+---------+--------------------------------------------+------------+
| id | form_id | user_id | timestamp |
+----+---------+--------------------------------------------+------------+
| 8 | 3 | anon-user-96684f301d22e7be44f07780a9bffe06 | 1663789158 |
| 9 | 3 | anon-user-a1eaa4f939b59e00b403c046410788aa | 1663835954 |
| 10 | 3 | anon-user-440d0dbe9c107492b6ec1a06d98004a8 | 1663942458 |
+----+---------+--------------------------------------------+------------+
the second table is oc_forms_v2_answers
SELECT * FROM `oc_forms_v2_answers`;
+----+---------------+-------------+-----------------------+
| id | submission_id | question_id | text |
+----+---------------+-------------+-----------------------+
| 10 | 8 | 7 | foo |
| 11 | 9 | 7 | bar |
| 12 | 10 | 7 | foo |
+----+---------------+-------------+-----------------------+
So basically i need to the take all the id entries from table submissions and match them with submission_id from answers and I want to have the data from the text column.
SELECT oc_forms_v2_submissions.id as submission_id
FROM `oc_forms_v2_submissions`
RIGHT JOIN `oc_forms_v2_answers` ON submission_id=oc_forms_v2_answers.submission_id;
This is all i could come up with so far but that returns only the submission_id field and everything triplicated :-D
+---------------+
| submission_id |
+---------------+
| 8 |
| 8 |
| 8 |
| 9 |
| 9 |
| 9 |
| 10 |
| 10 |
| 10 |
+---------------+
Edit:
The updated query still does not get me the field from oc_forms_answers:
SELECT oc_forms_v2_submissions.id as submission_id
FROM `oc_forms_v2_submissions`
RIGHT JOIN `oc_forms_v2_answers` ON oc_forms_v2_submissions.id=oc_forms_v2_answers.submission_id where form_id="3";
that is because you are comparing to identical columns, you need in the ON Clause, the link columns of both tables
Also you can use alias, to reduce the typing time
The RIGHT JOIN would also combine all answers with thes ubmission, but you you will never have more submission as answer, so a LEFT JOIN would gove ou all submissions even if there is no answer
SELECT oc_forms_v2_submissions.id as submission_id
FROM `oc_forms_v2_submissions`
LEFT JOIN `oc_forms_v2_answers` ON oc_forms_v2_submissions.id=oc_forms_v2_answers.submission_id;
This should do the trick (just update the correct naming of columns and tables)
SELECT s.id as submission_id, a.txt FROM submissions s
LEFT JOIN answers a
ON s.id=a.submission_id;
You can check this here in db-fiddle. I've used your info for creating a DB, so WHERE clause is missing but all the rest should give you results you're after.

SQL pivot table for unknown number of columns

I need some tips for the Postgres pivot below, please.
I have a table like this:
+------+---+----+
| round| id| kpi|
+------+---+----+
| 0 | 1 | 0.1|
| 1 | 1 | 0.2|
| 0 | 2 | 0.5|
| 1 | 2 | 0.4|
+------+---+----+
The number of Ids is unknown.
I need to convert the id column into multiple columns (same amount of different ids), with KPI value as their values and in the new table we keep the rounds like in the first table.
+------+----+----+
| round| id1| id2|
+------+----+----+
| 0 | 0.1| 0.5|
| 1 | 0.2| 0.4|
+------+----+----+
Is it possible to do this in SQL? How to do that?
It´s possible, check this question
This other is a pivot that I did, also with an unknown number of columns, maybe it can help you too: Advanced convert rows to columns (pivot) in SQL Server

SQL table transformation. How to pivot a certain table?

How would I do the pivot below?
I have a table like this:
+------+---+----+
| round| id| kpi|
+------+---+----+
| 0 | 1 | 0.1|
| 1 | 1 | 0.2|
| 0 | 2 | 0.5|
| 1 | 2 | 0.4|
+------+---+----+
I want to convert the id column into multiple columns (same amount of different ids), with KPI value as their values and in the new table we keep the rounds like in the first table.
+------+----+----+
| round| id1| id2|
+------+----+----+
| 0 | 0.1| 0.5|
| 1 | 0.2| 0.4|
+------+----+----+
Is it possible to do this in SQL? How to do that?
You are looking for a pivot function. You can find details on how to do this here and here. The first link also provides input into how to do this if you have an unknown number of columnnames.

In Hive, what is the difference between explode() and lateral view explode()

Assume there is a table employee:
+-----------+------------------+
| col_name | data_type |
+-----------+------------------+
| id | string |
| perf | map<string,int> |
+-----------+------------------+
and the data inside this table:
+-----+------------------------------------+--+
| id | perf |
+-----+------------------------------------+--+
| 1 | {"job":80,"person":70,"team":60} |
| 2 | {"job":60,"team":80} |
| 3 | {"job":90,"person":100,"team":70} |
+-----+------------------------------------+--+
I tried the following two queries but they all return the same result:
1. select explode(perf) from employee;
2. select key,value from employee lateral view explode(perf) as key,value;
The result:
+---------+--------+--+
| key | value |
+---------+--------+--+
| job | 80 |
| team | 60 |
| person | 70 |
| job | 60 |
| team | 80 |
| job | 90 |
| team | 70 |
| person | 100 |
+---------+--------+--+
So, what is the difference between them? I did not find suitable examples. Any help is appreciated.
For your particular case both queries are OK. But you can't use multiple explode() functions without lateral view. So, the query below will fail:
select explode(array(1,2)), explode(array(3, 4))
You'll need to write something like:
select
a_exp.a,
b_exp.b
from (select array(1, 2) as a, array(3, 4) as b) t
lateral view explode(t.a) a_exp as a
lateral view explode(t.b) b_exp as b

SELECTing Related Rows Based on a Single Row Match

I have the following table running on Postgres SQL 9.5:
+---+------------+-------------+
|ID | trans_id | message |
+---+------------+-------------+
| 1 | 1234567 | abc123-ef |
| 2 | 1234567 | def234-gh |
| 3 | 1234567 | ghi567-ij |
| 4 | 8902345 | ced123-ef |
| 5 | 8902345 | def234-bz |
| 6 | 8902345 | ghi567-ij |
| 7 | 6789012 | abc123-ab |
| 8 | 6789012 | def234-cd |
| 9 | 6789012 | ghi567-ef |
|10 | 4567890 | abc123-ab |
|11 | 4567890 | gex890-aj |
|12 | 4567890 | ghi567-ef |
+---+------------+-------------+
I am looking for the rows for each trans_id based on a LIKE query, like this:
SELECT * FROM table
WHERE message LIKE '%def-234%'
This, of course, returns just three rows, the three that match my pattern in the message column. What I am looking for, instead, is all the rows matching that trans_id in groups of messages that match. That is, if a single row matches the pattern, get all the rows with the trans_id of that matching row.
That is, the results would be:
+---+------------+-------------+
|ID | trans_id | message |
+---+------------+-------------+
| 1 | 1234567 | abc123-ef |
| 2 | 1234567 | def234-gh |
| 3 | 1234567 | ghi567-ij |
| 4 | 8902345 | ced123-ef |
| 5 | 8902345 | def234-bz |
| 6 | 8902345 | ghi567-ij |
| 7 | 6789012 | abc123-ab |
| 8 | 6789012 | def234-cd |
| 9 | 6789012 | ghi567-ef |
+---+------------+-------------+
Notice rows 10, 11, and 12 were not SELECTed because there was not one of them that matched the %def-234% pattern.
I have tried (and failed) to write a sub-query to get the all the related rows when a single message matches a pattern:
SELECT sub.*
FROM (
SELECT DISTINCT trans_id FROM table WHERE message LIKE '%def-234%'
) sub
WHERE table.trans_id = sub.trans_id
I could easily do this with two queries, but the first query to get a list of matching trans_ids to include in a WHERE trans_id IN (<huge list of trans_ids>) clause would be very large, and would not be a very inefficient way of doing this, and I believe there exists a way to do it with a single query.
Thank you!
This will do the job I think :
WITH sub AS (
SELECT trans_id
FROM table
WHERE message LIKE '%def-234%'
)
SELECT *
FROM table JOIN sub USING (trans_id);
Hope this help.
Try this:
SELECT ID, trans_id, message
FROM (
SELECT ID, trans_id, message,
COUNT(*) FILTER (WHERE message LIKE '%def234%')
OVER (PARTITION BY trans_id) AS pattern_cnt
FROM mytable) AS t
WHERE pattern_cnt >= 1
Using a FILTER clause in the windowed version of COUNT function we can get the number of records matching the predefined pattern within each trans_id slice. The outer query uses this count to filter out irrelevant slices.
Demo here
You can do this.
WITH trans
AS
(SELECT DISTINCT trans_id
FROM t1
WHERE message LIKE '%def234%')
SELECT t1.*
FROM t1,
trans
WHERE t1.trans_id = trans.trans_id;
I think this will perform better. If you have enough data, you can do an explain on both Sub query and CTE and compare the output.