Can use select into with multiple cte? for example in the below code the result of the first cte cte_table is inserted into dbo.table1, then the other cte is defined. is this possible?
WITH cte_table
AS
(
SELECT *
FROM dbo.table
)
INSERT INTO dbo.table1
SELECT *
FROM [cte_table]
, cte_table2
AS
(
SELECT *
FROM dbo.table2
)
Chain all your CTEs and THEN do the select into.
WITH First_CTE AS
(
SELECT
Columns
FROM
Schema.Table
WHERE
Conditions
),
Second_CTE AS
(
SELECT
Columns
FROM
Schema.OtherTable
WHERE
Conditions
)
SELECT
Variables
INTO
NewTable
FROM
First_CTE A
JOIN
Second_CTE B
ON
A.MatchVar = B.MatchVar
This can be helpful if you have no need of the CTEs later but prefer a simpler method than subqueries for your ETL.
If your case is Re-usability of the record set, in that case use a Temp Table or Table variable.
e.g.
Select * Into #temp1 From dbo.table
INSERT INTO dbo.table1
SELECT * FROM #temp1
SELECT * FROM #temp1 ..... and do some other re-usability operations.
A chained Cte work as under (just an example)
;With Cte1 As ( Select * from table1)
,Cte2 As (Select * from table2)
select c1.*,c2.*
from cte1 c1, cte2 c2
Hope you understand when to use what and how.
No you can't: you get an error as INTO is not allowed, and, as others have pointed out, it makes sense as the CTE is intended to be a repeatable (and thereby static) reference.
And I recall reading somewhere that is/was in large part syntactical sugar, in so far as the cte is resolved out into a derived table when the sql is executed.
No You cant use select into in CTE. And it actually does not make any sense also.
Related
I want to know if it's possible to make a where clause compare 2 columns to the same subquery. I know I could make a temp table/ variable table or write the same subquery twice. But I want to avoid all that if possible. The Subquery is long and complex and will cause significant overhead if I have to write it twice.
Here is an example of what I am trying to do.
SELECT * FROM Table WHERE (Column1 OR Column2) IN (Select column from TABLE)
I'm looking for a simple answer and that might just be NO but if it's possible without anything too elaborate please clue me in.
I updated the select to use OR instead of AND as this clarified my question a little better.
The example you've given would probably perform best using exists, such as:
select *
from t1
where exists (
select 1 from t2
where t2.col = t1.col1 and t2.col = t1.col2
);
To prevent writing the complicated subquery twice, you can use a CTE (Common Table Expression):
;WITH MyFirstCTE (x) AS
(
SELECT [column] FROM [TABLE1]
-- add all the very complicated stuff here
)
SELECT *
FROM Table2
WHERE Column1 IN (SELECT x FROM MyFirstCTE)
AND Column2 IN (SELECT x FROM MyFirstCTE)
Or using EXISTS:
;WITH MyFirstCTE (x) AS
(
SELECT [column] FROM [TABLE1]
-- add all the very complicated stuff here
)
SELECT *
FROM Table2
WHERE EXISTS (SELECT 1 FROM MyFirstCTE WHERE x = Column1)
AND EXISTS (SELECT 1 FROM MyFirstCTE WHERE x = Column2)
I used deliberately clumsy names, best to pick better ones.
I started it with a ; because if it's not the first command in a larger script then a ; is needed to separate the CTE from the commands before it.
Is there a way to write
SELECT count(*) from tablename where (multiple_ids_here) in (SELECT id from tablename)
Normally, I would write:
select count(*) from tablename
where id_1 in (SELECT id from tablename)
OR id_2 in (SELECT id from tablename)
id_3 in (SELECT id from tablename)
which very inefficient if we have multiple values.
Anyone?
EDIT: Question updated. What if I want to select count?
Your version with three ins is probably the most efficient way of doing this. If you want a comparison to try, you can use exists:
select . . .
from t t1
where exists (select 1
from tablename t2
where t2.id in (t1.id_1, t1.id_2, t1.id_3)
);
I should also note that storing ids in multiple columns like this is usually a sign of a problem with the data model. You probably want a table with one row per id, rather than one column per id. Such a format would also simplify this type of query.
For the updated question regarding getting a count(*)... using cross apply() with values() to unpivot your data in a common table expression:
;with cte as (
select t.Id, v.RelatedId
from t
cross apply (values (id_1),(id_2),(id_3)) v(RelatedId)
)
select
cte.Id
, RelationCount = count(*)
from cte
inner join RelatedTable r
on cte.RelatedId = r.Id
group by cte.Id
I am not sure i understand your question could you give an example of the data you are using and the out come.
From what i understand you could use a cte like this .
;WITH Sales_CTE ([counts],CustomerID, SalespersonPersonID,PickedByPersonID)
AS
(
select count(*),CustomerID,SalespersonPersonID ,PickedByPersonID
from [WideWorldImporters].[Sales].[Orders]
group by CustomerID,SalespersonPersonID,PickedByPersonID
)
SELECT sum([counts])
FROM Sales_CTE
GO
It would give you a result like this . You would jsut have to change the columns around .
I need to create a #temp table before my list of CTE:s start so that I can use it in the end to perform calculations.
This is what I have written so far:
SELECT DISTINCT
SUM(X+Y) AS Total
INTO #Summary
FROM Table
WITH CTE_START AS
(
SELECT DISTINCT *
FROM TableX
)
....
I have even tried creating my #Summary as a CTE and then writing INTO before FROM. It does not work.
I have looked at similar questions on:CTE&Temp Table
I have not found anything helpful. How can I create a #temp table before my WITH CTE_START begins processing?
You need to terminate the statement before the CTE with a semicolon, otherwise SQL Server doesn't know the WITH isn't part of the previous statement, for example part of a table hint.
For example:
SELECT DISTINCT SUM(X+Y) AS Total INTO #Summary FROM Table;
WITH CTE_START AS ( SELECT DISTINCT * FROM TableX )
SELECT * FROM CTE_START
Please don't mark this question as duplicate of CTE within a CTE .. I checked that question and answer ... but that answer does not satisfy my need.
I want to run Nested CTE query like this
Drop Table #Temp
Create Table #Temp(name1 text, name2 text)
Insert INTO #Temp Values ('test','test')
Insert INTO #Temp Values ('test','test')
;WITH CTE1 AS (
With CTE2 as ( Select * from #Temp)
)
Select * from CTE1
or
;WITH CTE1 AS (
Select * From (With CTE2 as ( Select * from #Temp))
)
Select * from CTE1
In our structure... the inner CTE2 query have been provided by other system .. so I can't control
inner part of the query... so.. here my duty is only select values from inner query and form new CTE in my system ...
And please imagine this
;WITH CTE1 AS (
"Query Provide by Other System"
)
In some cases the "Query Provide by Other System" start with CTE..this may or may not be the CTE query... that is the exact problem for I can't use like below
;WITH CTE1 AS (
Select * From
)
,With CTE2 as
( Select * from #Temp))
pls help anyone to prcoeed this, I guess my need is too dynamic
Just to have an idea:
;WITH cte1 AS
(
SELECT * FROM ...
),
cte2 as
(
SELECT * FROM ...
),
cte3 as
(
SELECT * FROM ... INNER JOIN cte2 ON...
),
SELECT *
FROM
cte1
INNER JOIN cte3 ON ...
Separate your CTEs with ,s rather than nesting them.
;
WITH
CTE2 AS
(
SELECT * FROM #Temp
)
,
CTE1 AS
(
SELECT * FROM CTE2
)
SELECT
*
FROM
CTE1
EDIT : Following your additional comments
As I understand it, you are being provided with a system generated query that you then want to embed in another query. Sometimes that system generated query uses a CTE, sometimes it doesn't; you don't know in advance the format of that query.
Unfortunately for you this means that you can not embed this within another CTE.
One option could be to use real views.
CREATE VIEW xxx AS
<system generated code here>
;
SELECT
*
FROM
xxx
;
You do then, however, have to be very careful about concurrency; two concurrent users trying to create the same view with the same name.
The better solution would be to approach the vendor of the system with is creating the system generated query and ask them how they propose you use it.
;with BASE AS (
SELECT * FROM table1
), BASE2 AS (
SELECT * from table2
), BASE3 AS (
SELECT * FROM table3
) SELECT * FROM BASE INNER JOIN BASE3 ...
I guess this is what you are trying to do.
If your system generated query uses db qualified object names you can hack this by using OPENQUERY:
WITH CTE AS
( SELECT *
FROM OPENQUERY([Your Server], 'Query Provide by Other System')
)
SELECT *
FROM CTE;
You may need to configure your server for data access:
EXEC sp_serveroption 'your server', 'DATA ACCESS', TRUE;
Expanding on following question (Multiple Select Statement) I would like to know if I can do following:
WITH
cte1 as (
SELECT * from cdr.Location
),
cte2 as (
SELECT * from cdr.Location
WHERE cdr.Location.someField = cte1.SomeField
)
select * from cte1 union select * from cte2
So accent here is on following line:
WHERE cdr.Location.someField = cte1.SomeField
where within cte2 I'm referencing cte1 ?
Yes, you can reference previously declared CTEs in subsequent CTEs:
WITH cte1 as (
SELECT t.*
FROM cdr.Location t),
cte2 as (
SELECT t.*
FROM cdr.Location t
JOIN cte1 c1 ON c1.somefield = t.someField)
SELECT *
FROM cte1
UNION
SELECT *
FROM cte2
NOTES
Joining onto cte2 in the cte1 declaration wouldn't work, because the statement is executed from top down.
You reference a CTE like any other inline view (which it is) or table/temp table/etc by JOINing on whatever you need.
BTW: Try to formulate a better example in the future - it's good for you and the rest of the SO community who are trying to help you.