Multiple reusable SQL queries - sql

(Note I am getting an error submitting to stackoverflow if i use "select", so have misspelled my queries. [Now Fixed])
Sorry this is a newbie question. I have one very long SQL query that is getting harder to manage. In fact there are some sub-queries that are being used multiple times. What is the best way to break up the query? I would prefer to keep it in the database, rather than take it out into the calling program. It goes something like this.
Select A, B, C
from (select D from Table_1 where ...)
Union Select E, F
from Table_2
Inner Join (Select D, E, from Table_1 where...)..
So what I would like to do is
Result1 = select D,E from Table_1 where....
Result2 = Select A,B,C from Result_1 Union Select E,F from Table_2 Inner Join Result_1 ...
What is the best way to do this? I can't use Views because I don't have privileges. How can I use the results from the first query in the second query? Can cursors be used in this case?

Using a CTE you can access the same subquery multiple times (this is the main difference to Derived Tables):
with CTE as
(Select D, E, from Table_1 where...)
Select A, B, C
from CTE
Union
Select E, F
from Table_2
Inner Join CTE ..

Related

Can i run more then one main select statments on the 2 with tables?

Hay All,
is it possible to run more than 1 select statement after using with?
first select statement works fine, as soon as i add another select statement i got a error.
with
a as (select a,b,c from Table1 with(readuncommitted)),
b as (select d,e,f from Table2 with(readuncommitted))
select * from a
select * from b
expected output:
Table 1
a
Table 2
b
Well the way CTEs will behave is that they will only be in scope for the first query, but not the second. You could perhaps do a union query here:
SELECT a, b, c, 'Table1' AS src FROM a
UNION ALL
SELECT d, e, f, 'Table2' FROM b;
Or, you could move the b CTE to before the second query:
WITH a AS (
SELECT a, b, c
FROM Table1
WITH(readuncommitted)
)
SELECT * FROM a;
WITH b AS (
SELECT d, e, f
FROM Table2
WITH(readuncommitted)
)
SELECT * FROM b;
hay DasD,
You can not use multiple select for cte, but you can use more than one CTE like this.
with
a as (select a,b,c from Table1 with(readuncommitted)),
b as (select d,e,f from Table2 with(readuncommitted))
select * from a,b
You have to explain to the database, what you wantfrom bith tables.
as both have the same structure you can use UNION to join them vertically
with
a as (select a,b,c from Table1 with(readuncommitted)),
b as (select d,e,f from Table2 with(readuncommitted))
select * from a
UNION
select * from b
From the docs:
"A CTE must be followed by a single SELECT, INSERT, UPDATE, or DELETE statement that references some or all the CTE columns."
Source

How to write a subquery in a select statement in hive

I have the need to write a Hive query that has a subquery in the select statement. Im aware that Hive does not support this, therefore I'm looking out for my options.
select
a,
b,
(select max(tbl.c) from sample_table_a tbl where tbl.d like 'X012%') as d,
e,
f
from sample_table_b
How can I implement the above query in hive without using a cross join because sample_table_a contains about 40000 tuples and so does the sample_table_b.
This could be an option:
There is going to be a single row in table t so join should not be that much a problem
select
a,
b,
max_value,
e,
f
from
sample_table_b
inner join
(
select
max(tbl.c) as max_value
from
sample_table_a tbl
where
tbl.d like 'X012%'
)
t;

Can I select several tables in the same WITH query?

I have a long query with a with structure. At the end of it, I'd like to output two tables. Is this possible?
(The tables and queries are in snowflake SQL by the way.)
The code looks like this:
with table_a as (
select id,
product_a
from x.x ),
table_b as (
select id,
product_b
from x.y ),
table_c as (
..... many more alias tables and subqueries here .....
)
select * from table_g where z = 3 ;
But for the very last row, I'd like to query table_g twice, once with z = 3 and once with another condition, so I get two tables as the result. Is there a way of doing that (ending with two queries rather than just one) or do I have to re-run the whole code for each table I want as output?
One query = One result set. That's just the way that RDBMS's work.
A CTE (WITH statement) is just syntactic sugar for a subquery.
For instance, a query similar to yours:
with table_a as (
select id,
product_a
from x.x ),
table_b as (
select id,
product_b
from x.y ),
table_c as (
select id,
product_c
from x.z ),
select *
from table_a
inner join table_b on table_a.id = table_b.id
inner join table_c on table_b.id = table_c.id;
Is 100% identical to:
select *
from
(select id, product_a from x.x) table_a
inner join (select id, product_b from x.y) table_b
on table_a.id = table_b.id
inner join (select id, product_c from x.z) table_c
on table_b.id = table_c.id
The CTE version doesn't give you any extra features that aren't available in the non-cte version (with the exception of a recursive cte) and the execution path will be 100% the same (EDIT: Please see Simon's answer and comment below where he notes that Snowflake may materialize the derived table defined by the CTE so that it only has to perform that step once should the CTE be referenced multiple times in the main query). As such there is still no way to get a second result set from the single query.
While they are the same syntactically, they don't have the same performance plan.
The first case can be when one of the stages in the CTE is expensive, and is reused via other CTE's or join to many times, under Snowflake, use them as a CTE I have witness it running the "expensive" part only a single time, which can be good so for example like this.
WITH expensive_select AS (
SELECT a.a, b.b, c.c
FROM table_a AS a
JOIN table_b AS b
JOIN table_c AS c
WHERE complex_filters
), do_some_thing_with_results AS (
SELECT stuff
FROM expensive_select
WHERE filters_1
), do_some_agregation AS (
SELECT a, SUM(b) as sum_b
FROM expensive_select
WHERE filters_2
)
SELECT a.a
,a.b
,b.stuff
,c.sum_b
FROM expensive_select AS a
LEFT JOIN do_some_thing_with_results AS b ON a.a = b.a
LEFT JOIN do_some_agregation AS c ON a.a = b.a;
This was originally unrolled, and the expensive part was some VIEWS that the date range filter that was applied at the top level were not getting pushed down (due to window functions) so resulted in full table scans, multiple times. Where pushing them into the CTE the cost was paid once. (In our case putting date range filters in the CTE made Snowflake notice the filters and push them down into the view, and things can change, a few weeks later the original code ran as good as the modified, so they "fixed" something)
In other cases, like this the different paths that used the CTE use smaller sub-sets of the results, so using the CTE reduced the remote IO so improved performance, there then was more stalls in the execution plan.
I also use CTEs like this to make the code easier to read, but giving the CTE a meaningful name, but the aliasing it to something short, for use. Really love that.

How to use a table alias with a Union statement in Access?

In an unpivoting operation, I would like the following:
SELECT A, B, C FROM [complex joins/where clause] As DerivedTable
UNION
SELECT A, B, D FROM DerivedTable
UNION
SELECT A, B, E FROM DerivedTable
...
but it complains that DerivedTable cannot be found (I use a derived table so that [complex joins/where clause] doesn't have to be evaluated again and again thereby slowing things).
I know I can simply create a new query called DerivedTable to represent [complex joins/where clause] but
The above SQL is passed from Excel - I'd rather not have to open the database to create a new query prior to running the above
The [complex joins/where clause] is generated dynamically, and changes from user to user, two of which may be running the above SQL at the same time.
Something like this. Use CASE and JOIN this table with (1,2,3,...) table. I'm not sure it is right syntax for Access but it will work on most SQL dialects.
SQLFiddle demo
SELECT A,B,
CASE WHEN CT.r=1 then C
WHEN CT.r=2 then D
WHEN CT.r=3 then E
END
FROM [complex joins/where clause] As DerivedTable
CROSS JOIN (select 1 as r
union all
select 2 as r
union all
select 3 as r
) as CT
order by A,B

SQL join on many queries

I have a table with a structure such as table(PK, a, b, c, d, e, f, g).
And I have many queries that I want to join:
select PK, sum(c) where...
JOIN
select PK, sum(e) where...
JOIN
select PK, sum(g) where ...
JOIN
select PK,a,b,d,f
Every sum(c|e|g) is actually a
select sum(c|e|g) from .... where...
because there are many conditions involved (not all c|e|g's must be added)
Is this the best way to do it? I was suggested to write it in PL / SQL, which I would have to learn. If its the way to go, i'll do it, but im not sure whats wrong with the solution shown above.
Edit
Im pretty sure its a Join. Here's what I want.
I need to get a result set in the form:
PK, a,b,COMPLEX_SUM_ON_C,d,COMPLEX_SUM_ON_D,f,COMPLEX_DUM_ON_G
so I thought of joining many queries to get this result.
Each of the COMPLEX... is another select (select sum...). This is a very big table, and writing
select a,b,(select sum..),d,(select sum...),f,(select sum...)
will yield bad performance (so I was told to remove it)
I've edited my query above.
Thanks in advance.
I think you mean "UNION" not "JOIN". Whether is the best way depends on what you're trying to achieve.
This is not a well-defined problem (yet).
Assuming PK is your primary key (i.e. unique, by definition), then
SELECT PK, SUM(c)
FROM tbl
GROUP BY PK
is ALWAYS the same as
SELECT PK, c
FROM tbl
So grouping (and aggregating) is relatively meaningless.
In your expected results:
PK, a,b,COMPLEX_SUM_ON_C,d,COMPLEX_SUM_ON_D,f,COMPLEX_DUM_ON_G
How are COMPLEX_SUM_ON_C, COMPLEX_SUM_ON_D, COMPLEX_DUM_ON_G related to PK?
We know how a, b, d, f are related to PK, because for each PK, one can identify the one and only a, b, d, f on the same row.
An example of a JOIN is the following:
Select a.col1, b.col2
FROM table1 a, table2 b
WHERE a.key = b.key;
which can also be written:
SELECT a.col1, b.col2
FROM table1 a
INNER JOIN table2 b
ON a.key = b.key;
Edit:
After reading your re-edit of the original question, you can probably use a JOIN. JOINs can be used when you have related data in more than one table, or you can specifiy the same table multiple times. I have used both kinds with Oracle. Here's an example of the latter kind which will hopefully help you:
SELECT t1.a, t1.b, t3.sum(c), t2.d, t4.sum(e), t1.f, t5.sum(g)
FROM table1 t1, table1 t2, table1 t3, table1 t4, table1 t5
WHERE t1.a = 'hello'
AND t2.a = 'world'
AND t3.c = 10
AND t4.e = 20
AND t5.g = 100
GROUP BY t1.a, t1.b, t2.d, t1.f;