Does Snowflake allow you to create a series of CTEs then join them together at the end to create a table?
For example:
with CTE1 as ( SELECT * FROM TABLE1)
,CTE2 AS (SELECT * FROM TABLE2)
,CTE3 AS (SELECT * FROM TABLE3)
CREATE TABLE TABLE_NAME_HERE AS
SELECT * FROM CTE1 AS 1
LEFT JOIN CTE2 AS 2 ON 1.KEY = 2.KEY
LEFT JOIN CTE3 AS 3 ON 1.KEY = 3.KEY
I'm getting a unexpected 'CREATE'. error
It's an interesting one, because that CTAS (CREATE TABLE AS) form is
CREATE TABLE <name> AS <select>
and SELECT form is can have a CTE and a CTE form is
WITH <name> AS <select>
CTE can also be in sub-select given "it's just a select", thus
SELECT <columns>
FROM (
WITH cte_1 AS (
SELECT <columns>
FROM table
)
SELECT <columns>
FROM cte_1
)
which shows why the form that Lukasz shows is correct because if we add more parens
CREATE TABLE name AS (
WITH cte_1 AS (
SELECT <columns>
FROM table
)
SELECT <columns>
FROM cte_1
)
Yes, it is possible:
CREATE TABLE TABLE_NAME_HERE AS
WITH CTE1 as ( SELECT * FROM TABLE1)
,CTE2 AS (SELECT * FROM TABLE2)
,CTE3 AS (SELECT * FROM TABLE3)
SELECT * -- here should be explicit column list to avoid name duplication error
FROM CTE1 AS 1
LEFT JOIN CTE2 AS 2 ON 1.KEY = 2.KEY
LEFT JOIN CTE3 AS 3 ON 1.KEY = 3.KEY;
Related
I have a sql server table showing the IDs and their previous IDs,
create table test2 ( ID varchar(10) ,
Pre_ID varchar(10)
)
insert into test2 values ('e','d')
, ('d','c')
, ('c','b')
, ('b','a')
, ('a',null)
, ('r','q')
, ('q','p')
, ('p',null)
the table is like this:
The result should be like this:
I have successfully got the levels using a recursive cte, but could not get the correct group for them. can anyone help? Thanks.
This is my code:
with cte as (
select id, Pre_ID, level
from #temp2
where Pre_ID is null
union all
select t2.id, t2.Pre_ID, t2.level
from cte
inner join #temp2 t2
on t2.Pre_ID=cte.id
)
select * from cte
order by id
What you need to do is start with the first level and add a ROW_NUMBER to that, then join all further levels recursively:
with cte as (
select id, Pre_ID, level, row_number() over (order by ID) as grp
from #temp2
where Pre_ID is null
union all
select t2.id, t2.Pre_ID, t2.level, cte.grp
from cte
inner join #temp2 t2
on t2.Pre_ID=cte.id
)
select * from cte
order by id;
I have an SQL Server query that uses some CTEs (Common Table Expressions). It has two tables that it selects the data from. The two tables are identical in structure, but not necessary data. The query will first select from table_a and if no rows are fetched, it then selects from table_b. The query is something like this:
;WITH cte_a AS (
...
), cte_b AS (
...
)
SELECT *
FROM table_a
INNER JOIN cte_a ON condition_a
OR NOT EXISTS (
SELECT *
FROM table_b
INNER JOIN cte_b ON condition_b
)
The current problem that I have is that cte_b will always be executed regardless of whether table_a returns any rows. This is not very ideal for me; I would like to have cte_b execute if and only if the subquery for table_a returns no rows.
I tried moving the cte_b to be just before the subquery for table_b as
;WITH cte_a AS (
...
)
SELECT *
FROM table_a
INNER JOIN cte_a ON condition_a
OR NOT EXISTS (
;WITH cte_b AS (
...
)
SELECT *
FROM table_b
INNER JOIN cte_b ON condition_b
)
However, the IDE complains. I think that this wasn't the way CTEs are supposed to be used.
Create temporary table for storing the data - split the query to two separate INSERT statements, where the second is executed only in no data is populated after first query is completed. Something like this:
CREATE TABLE #TEmp
(
);
;WITH cte_a AS (
...
)
INSERT INTO #TEmp
SELECT *
FROM table_a
INNER JOIN cte_a ON condition_a
IF NOT EXISTS(SELECT 1 FROM #TEmp)
BEGIN;
INSERT INTO #TEmp
SELECT *
FROM table_a
WHERE NOT EXISTS (
SELECT *
FROM table_b
INNER JOIN cte_b ON condition_b
)
This is the nature of CTE's.
The best thing would be to not use a CTE and use a join, but I assume you can't.
I'd suggest you try using a sub-query so the engine can process it all at once.
I would phrase this using a union, and then excluding the second half of the union on cte_b should the first CTE have any results.
;WITH cte_a AS (
...
),
cte_b AS (
...
)
SELECT *
FROM table_a
INNER JOIN cte_a ON condition_a
UNION ALL
SELECT *
FROM table_b
INNER JOIN cte_b ON condition_b
WHERE NOT EXISTS (
SELECT 1
FROM table_a
INNER JOIN cte_a ON condition_a
)
;WITH cte1 AS
(
....
),
cte2 AS
(
...
)
SELECT *
FROM table_a
INNER JOIN cte_a ON condition_a ---Choose Your Condition...
UNION ALL
SELECT *
FROM table_b
INNER JOIN cte_b ON condition_b ---Choose Your Condtion....
WHERE NOT EXISTS (SELECT * FROM cte2)
Note:-
A CTE must be followed by a single SELECT, INSERT, UPDATE, or DELETE statement that references some or all the CTE columns.
I am stuck with this. I have a simple set-up with two tables. One table is holding emailaddresses one table is holding vouchercodes. I want to join them in a third table, so that each emailaddress has one random vouchercode.
Unfortunatly I am stuck with this as there are no identic Ids to match both values. What I have so far brings no result:
Select
A.Email
B.CouponCode
FROM Emailaddresses as A
JOIN CouponCodes as B
on A.Email = B.CouponCode
A hint would be great as search did not bring me any further yet.
Edit -
Table A (Addresses)
-------------------
Column A | Column B
-------------------------
email1#gmail.com True
email2#gmail.com
email3#gmail.com True
email4#gmail.com
Table B (Voucher)
-------------------
ABCD1234
ABCD5678
ABCD9876
ABCD5432
Table C
-------------------------
column A | column B
-------------------------
email1#gmail.com ABCD1234
email2#gmail.com ABCD5678
email3#gmail.com ABCD9876
email4#gmail.com ABCD5432
Sample Data:
While joining without proper keys is not a good solution, for your case you can try this. (note: not tested, just a quick suggestion)
;with cte_email as (
select row_number() over (order by Email) as rownum, Email
from Emailaddresses
)
;with cte_coupon as (
select row_number() over (order by CouponCode) as rownum, CouponCode
from CouponCodes
)
select a.Email,b.CouponCode
from cte_email a
join cte_coupon b
on a.rownum = b.rownum
You want to randomly join records, one email with one coupon each. So create random row numbers and join on these:
select
e.email,
c.couponcode
from (select t.*, row_number() over (order by newid()) as rn from emailaddresses t) e
join (select t.*, row_number() over (order by newid()) as rn from CouponCodes t) c
on c.rn = e.rn;
Give a row number for both the tables and join it with row number.
Query
;with cte as(
select [rn] = row_number() over(
order by [Column_A]
), *
from [Table_A]
),
cte2 as(
select [rn] = row_number() over(
order by [Column_A]
), *
from [Table_B]
)
select t1.[Column_A] as [Email_Id], t2.[Column_A] as [Coupon]
from cte t1
join cte2 t2
on t1.rn = t2.rn;
Find a demo here
I have the following structure:
Create #temp
Select ...inser...into #temp where ...
(select ... from #temp
Join tblA where ... )
UNION
(Select ... from #temp
join tblB where ... )
After build above table I need to be able to perform WHERE, JOINS, ...
Something like:
Select ... from (above statement)
join ....
where....
I don't know how of if a #temp,joins, union... can be inside other select.
OR only thing I can do is create a #Temp2 inserting with first statement result and then work with other join,where... ?
UPDATE 1:
I also trying:
With cte (query returned columns)
as
(same query I was using to build my #temp as before)
(select ... from cte
join tblA
where...)
UNION
(select ... from cte
join tblB
where...)
But Im stuck at same point in how to perform other joins, where... with above total result
Create #temp
Select ...inser...into #temp where ...
;with temp2 as
(
select ... from #temp Join tblA where ...
UNION
Select ... from #temp join tblB where ...
)
select ... from temp2
join ....
where....
Actually you can do it without temp-table:
WITH myCTE [ ( column_name [,...n] ) ]
AS
( here you define your query )
and after that you just do your Select but use CTE
Select ... from myCTE
join ....
where....
about CTE you can read Here
After Update
Select fields from myCTE join table1
Union
Select fields from myCTE join table2
Without brackets in your query
I want to use left outer join like this:
SELECT ...
FROM Table1
LEFT OUTER JOIN
(SELECT only e.g. 3rd record... , SomeField FROM Table2) tbl2
ON Table1.SomeField = tbl2.SomeField
How can I do that, if I need the subquery to select not just the 3rd record from Table2, but the 3rd record among the Table2 records that have SomeField = Table1.SomeField?
Thanks.
If this is sql server 2005 or newer, you might use row_number():
LEFT JOIN
(
select *
from
(
select *,
row_number() over (order by something) rn
from Table2
where Table2.Column = Table1.Column
) a
where a.rn = 3
) a
Unfortunately you need to nest it a level deeper because you cannot use row_number in a condition directly.
EDIT:
My bad - i didn't really notice the join part. If you want to join derived table, use this:
LEFT JOIN
(
select *,
row_number() over (partition by SomeField order by something) rn
from Table2
) tbl2
ON Table1.SomeField = tbl2.SomeField
AND tbl2.rn = 3
Note: you need ORDER BY in row_number() to keep things consistent.