In Windows Server, I am trying to gather data using multiple CTEs insert them into a few temp tables to later on perform a join. Below is what I got. :
------TEMP TABLE SET UP------
IF EXISTS (
SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = Object_id(N'tempdb..#LEFT')
)
BEGIN
DROP TABLE #LEFT
END
IF EXISTS (
SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = Object_id(N'tempdb..#RIGHT')
)
BEGIN
DROP TABLE #RIGHT
END
------TEMP TABLE SET UP END------
------CTE SET UP------
; with
CTEfirst (1a, b, c, d) as
(select 1a, b, c, d from tableA)
, CTEone (a, b, c) as
(select a, b, c from table1)
),
CTEtwo (a, b, c) as (
(select a, b, c from table2)
),
CTEthree (a, b, c) as (
(select a, b, c from table3)
------CTE SET UP END------
select * into #LEFT from CTEone
union
select * from CTEtwo
union
select * from CTEthree
-----------------------------
/*At this point I am getting the issue to recognize CTEfirst when attempting to insert data into #RIGHT temp table unless I move the below portion below the previous section (prior to the unions) but then would encounter the issue of the overall query not recognizing the next CTE, CTEone.*/
select * into #RIGHT from CTEfirst
Thank you
you have declared cte but it is empty
; with
CTEfirst (a, b, c, d)
as ( select ...) --<-- missing cte definiation here
, CTEone (a, b, c) as
(select a, b, c from table1)
),
You cannot refer to the same CTE for more than one unattached select statement.
Your first query ends when you insert into #left.
After that you cannot run a new select statement referring to the same (unattached) CTEs.
Think of CTEs as reformatted sub-queries. If you want data loaded into multiple temp tables, I wouldn't use CTEs in the first place. Just insert into the temp tables directly.
Related
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
Let's say I would like to pull the fields dim,a,b,c,d from 2 tables which one contains a,b and the other contains c,d.
I'm wondering if there's a preferred way (between the following) to do it - Performance wise:
1:
select t1.dim,a,b,c,d
from
(select dim,sum(a) as a,sum(b)as b from t1 group by dim)t1
join
(select dim,sum(c) as c,sum(d) as d from t2 group by dim)t2
on t1.dim=t2.dim;
2:
select dim,sum(a) as a,sum(b) as b,sum(c) as c,sum(d) as d
from
(
select dim,a,b,null as c, null as d from t1
union
select dim,null as a, null as b, c, d from t2
)a
group by dim
Of course when handling a large amount of data (5-30M records at the final query).
Thanks!
The first method filters would any dim values that are not in both tables. union is inefficient. So, neither is appealing.
I would go for:
select dim, sum(a) as a, sum(b) as b, sum(c) as c, sum(d) as d
from (select dim, a, b, null as c, null as d from t1
union all
select dim, null as a, null as b, c, d from t2
) a
group by dim;
You could also pre-aggregate the values in each subquery. Or use full outer join for the first method.
My code is like this
SELECT A, B, C
FROM tb_1
WHERE C = (SELECT CASE WHEN (B > C) THEN C ELSE NULL END FROM tb_2)
I want to select row from tb_1 with specified condition. When result of subquery is value of column C, it works well. But when the result is NULL, it cannot select the data. Because SQL Server cannot execute something like this
SELECT A, B, C
FROM tb_1
WHERE C = NULL
but, it should be like this
SELECT A, B, C
FROM tb_1
WHERE C IS NULL
Can anybody help me? I still want to insert subquery (select case when) to that condition
Thanks
The table tb_2 design is not clear from your question. Assuming the tb_2 structure be same as tb_1, I think the following would work, but it all depends on your data (especially values in the column C). For example, if the values saved in C never be -9999, then you could use ISNULL in the WHERE clause as below. However, I would recommend to avoid subqueries where possible.
WHERE ISNULL(C, -9999) IN (SELECT CASE WHEN (B > C) THEN ISNULL(C, -9999) ELSE -9999 END FROM #t2)
Illustration:
GO
DECLARE #T1 TABLE (A INT, B INT, C INT)
INSERT INTO #T1 (A, B)VALUES (10, 20),(1, 2)
DECLARE #T2 TABLE (A INT, B INT, C INT)
INSERT INTO #T2 (A, B)VALUES (10, 20),(1, 2)
SELECT A, B, C
FROM #t1
WHERE ISNULL(C, -9999) IN (SELECT CASE WHEN (A > B) THEN ISNULL(C, -9999) ELSE -9999 END FROM #t2)
For a table such as this:
tblA
A,B,C
1,2,t3a
1,3,d4g
1,2,b5e
1,3,s6u
I want to produce a table that selects distinct on both A and B simultaneously, and still keep one value of C, like so:
tblB
A,B,C
1,2,t3a
1,3,d4g
Seems like this would be simple, but not finding it for the life of me.
DROP TABLE IF EXISTS tblA CASCADE;
SELECT DISTINCT ON (A,B), C
INTO tblB
FROM tblA;
When you use DISTINCT ON you should have ORDER BY:
SELECT DISTINCT ON (A,B), C
INTO tblB
FROM tblA
ORDER BY A, B;
This should do the trick
CREATE TABLE tblB AS (
SELECT A, B, max(C) AS max_of_C FROM tblA GROUP BY A, B
)
Use a view to do the distinct and then join it to the original table to pick one row of column C. Inserting into the target is left for you to figure out. Oh, and you could pick up multiple columns from t, not just c - the only thing is that your subquery needs to find a way to limit it to only one row.
create table t (a int, b int, c int);
create view tv as select distinct a, b from t;
insert into t (a, b, c) values(1, 2, 10);
insert into t (a, b, c) values(1, 2, 20);
insert into t (a, b, c) values(1, 3, 30);
insert into t (a, b, c) values(1, 3, 40);
CREATE TABLE tblB AS (
select tv.a, tv.b, t.c from tv, t
where tv.a = t.a and tv.b = t.b
/* pick smallest ctid which is a unique row id built into postgres */
and t.ctid = (select min(ctid) from t s where s.a = t.a and s.b = t.b);
)
I am attempting to define a conditional insert in postgresql, on an index over 3 columns (which gives uniqueness). I'm trying to follow the following example from the postgresql documentation:
INSERT INTO example_table
(id, name)
SELECT 1, 'John'
WHERE
NOT EXISTS (
SELECT id FROM example_table WHERE id = 1
);
For the basic SELECT WHERE NOT EXISTS structure. But if the index varies, i.e. you want to prevent insert if there exists a selection in the table with id=index value of current pre-insert row, how do you implement this? Here is my current (wrong) code:
insert = (
"INSERT INTO table (index,a,b,c,d,e)"
"SELECT * FROM table WHERE NOT EXISTS (SELECT * FROM table WHERE index=index)");
cur.execute(insert,data)
For clarity, the index is defined on data columns (a,b,c), data is a row of (index,a,b,c,d,e), and I'm wrapping this in psycopg2. I have searched for an answer for a while, but haven't been able to successfully adapt anything to this problem yet.
insert into t1 (a, b, c, d, e)
select a, b, c, d, e
from t2
where not exists (
select 1
from t1
where a = t2.a and b = t2.b and c = t2.c
);
In Python it is easier and cleaner to use the triple quote raw string
insert = """
insert into t1 (a, b, c, d, e)
select a, b, c, d, e
from t2
where not exists (
select 1
from t1
where a = t2.a and b = t2.b and c = t2.c
);
"""