Not Able to Query Multiple Times from Multiple Common Table Expressions (WITH)? - sql

I was doing some querying today in T-SQL, SQL-Server-2008 and stumbled upon something weird that I didn't understand. Using the query windows, I am trying to query from two common table expressions like so (I stripped out a lot of code to make it more obvious what I was doing):
;WITH temp1 AS (SELECT * FROM dbo.Log)
, temp2 AS (SELECT * FROM dbo.SignalCodeItems300_tbl)
SELECT * FROM temp1
SELECT * FROM temp2
However, only one of the select statements will run, the FIRST one. Regardless of which is which, only the first runs. I assume this is some sort of syntax thing that I'm missing maybe? I get the error "Invalid object name 'temp2'".
Could someone shed some light on this problem? Are there any workarounds for this?

No, this works as it should. A CTE (Common Table Expression) is only available for the first statement after the definition. So in other words, after select * from temp1, they both become unavailable.
The fix would be this:
;WITH temp1 AS (SELECT * FROM dbo.Log)
SELECT * FROM temp1
;WITH temp2 AS (SELECT * FROM dbo.SignalCodeItems300_tbl)
SELECT * FROM temp2

You might want to take a look at the MSDN documentation.
Especially:
Multiple CTE query definitions can be defined in a nonrecursive CTE.
The definitions must be combined by one of these set operators:
UNION ALL, UNION, INTERSECT, or EXCEPT.
You cannot mix and match two different schemas though, as this essentially runs as one query.

Use a view or a user-defined, table-valued function to house your query if you don't want to repeat it explicitly.

Related

Why isn't a CTE evaluated one time?

If we take the following:
WITH tbl AS (
SELECT RAND() AS a
) SELECT * FROM tbl AS tbl1, tbl AS tbl2
Why does this return two values instead of one? I thought a CTE is basically evaluated one time at the start and then it is used wherever it is needed? Or is my understanding of persistency of a CTE incorrect? Or does the implementation from db to db differ?
Compared with MySQL where it returns a single persisted-value:
According to the docs
BigQuery only materializes the results of recursive CTEs, but does not materialize the results of non-recursive CTEs inside the WITH clause. If a non-recursive CTE is referenced in multiple places in a query, then the CTE is executed once for each reference.
So what you see is expected at least for BigQuery.

Is Select * bad practice when selecting from a common table expression (cte) [duplicate]

The following post had compelling reasons for generally avoiding the use of select * in SQL.
Why is SELECT * considered harmful?
In the discussion was examples of when it was or wasn't acceptable to use select * However I did not see discussion on common table expression (CTE). Are there any drawbacks for using select * in CTEs?
Example:
WITH CTE1 AS
(
SELECT Doc, TotalDue
FROM ARInvoices
WHERE CustomerName = 'ABC'
UNION
SELECT Doc, - TotalDue
FROM ARInvoiceMemos
WHERE CustomerName = 'ABC'
)
select * from CTE1
UNION
Select 'Total' as Doc, sum(TotalDue)
FROM CTE1
Since you already properly listed the column names in the cte, I don't see any harm in using select * from the cte.
In fact, it might be just the right place to use select *, since there is no point of listing the columns twice.
Unless you don't need to use all the columns returned by the cte. (i.e a column in the cte is used on the query, but not in the select clause) In that case, I would suggest listing only the columns you need even of the from is pointing to a cte.
Note that if the cte itself uses select * then all of the drawbacks listed in the post you linked to applies to it.
My main objection to select * is that it's usually used by lazy developers that doesn't consider the consequences of the *.
Note: Everything I've written here applies to derived tables as well.
In theory the rule of thumb that select * is ill advised always applies.
In practice though, if you are a developer who considers things like design and general good programming practice as important as functionality, your CTE will most likely be coded to only return the columns which are actually needed, so select * from CTE1 might not be so bad.

Best Practice: Select * on CTE

The following post had compelling reasons for generally avoiding the use of select * in SQL.
Why is SELECT * considered harmful?
In the discussion was examples of when it was or wasn't acceptable to use select * However I did not see discussion on common table expression (CTE). Are there any drawbacks for using select * in CTEs?
Example:
WITH CTE1 AS
(
SELECT Doc, TotalDue
FROM ARInvoices
WHERE CustomerName = 'ABC'
UNION
SELECT Doc, - TotalDue
FROM ARInvoiceMemos
WHERE CustomerName = 'ABC'
)
select * from CTE1
UNION
Select 'Total' as Doc, sum(TotalDue)
FROM CTE1
Since you already properly listed the column names in the cte, I don't see any harm in using select * from the cte.
In fact, it might be just the right place to use select *, since there is no point of listing the columns twice.
Unless you don't need to use all the columns returned by the cte. (i.e a column in the cte is used on the query, but not in the select clause) In that case, I would suggest listing only the columns you need even of the from is pointing to a cte.
Note that if the cte itself uses select * then all of the drawbacks listed in the post you linked to applies to it.
My main objection to select * is that it's usually used by lazy developers that doesn't consider the consequences of the *.
Note: Everything I've written here applies to derived tables as well.
In theory the rule of thumb that select * is ill advised always applies.
In practice though, if you are a developer who considers things like design and general good programming practice as important as functionality, your CTE will most likely be coded to only return the columns which are actually needed, so select * from CTE1 might not be so bad.

How to refer to a variable create in the course of executing a query in T-SQL, in the WHERE clause?

What the title says, really.
If I SELECT [statement] AS whatever, why can't I refer to the whatever column in the body of the WHERE clause? Is there some kind of a workaround? It's driving me crazy.
As far as I'm aware, you can't directly do this in SQL Server.
If you REALLY have to use your column alias in the WHERE clause, you can do this, but it seems like overkill to use a subquery just for the alias:
SELECT *
FROM
(
SELECT [YourColumn] AS YourAlias, etc...
FROM Whatever
) YourSubquery
WHERE YourAlias > 2
You're almost certainly better off just using the contents of the original column in your WHERE clause.
It has to do with the way a SELECT statement gets translated into an abstract query tree: the 'whatever' only appears in the query result projection part of the tree, which is above the filtering part of the tree, so the WHERE clause cannot understand the 'whatever'. This is not some internal implementation detail, it is a fundamental behavior of relational queries: the projection of the result occurs after the evaluation of the joins and filters.
IS really trivial to work around the 'problem' by making the hierarchy of the query explicit:
select ...
from (
select [something] as whatever
from ...
) as subquery
WHERE whatever = ...;
A common table expression can also server the same purpose:
with cte as (
select [something] as whatever
from ...)
select ... from cte
WHERE whatever = ...;
It's to do with the order of operations in the select statement. The WHERE clause is evaluated before the SELECT clause so this information isn't available. Although it is available in the ORDER BY clause as this is processed last.
As others have mentioned, a sub-query will get around this problem.

SQL - Use results of a query as basis for two other queries in one statement

I'm doing a probability calculation. I have a query to calculate the total number of times an event occurs. From these events, I want to get the number of times a sub-event occurs. The query to get the total events is 25 lines long and I don't want to just copy + paste it twice.
I want to do two things to this query: calculate the number of rows in it, and calculate the number of rows in the result of a query on this query. Right now, the only way I can think of doing that is this (replace #total# with the complicated query to get all rows, and #conditions# with the less-complicated conditions that rows, from #total#, must have to match the sub-event):
SELECT (SELECT COUNT(*) FROM (#total#) AS t1 WHERE #conditions#) AS suboccurs,
COUNT(*) AS totaloccurs FROM (#total#) as t2
As you notice, #total# is repeated twice. Is there any way around this? Is there a better way to do what I'm trying to do?
To re-emphasize: #conditions# does depend on what #total# returns (it does stuff like t1.foo = bar).
Some final notes: #total# by itself takes ~250ms. This more complicated query takes ~300ms, so postgres is likely doing some optimization, itself. Still, the query looks terribly ugly with #total# literally pasted in twice.
If your sql supports subquery factoring, then rewriting it using the WITH statement is an option. It allows subqueries to be used more than once. With will create them as either an inline-view or a temporary table in Oracle.
Here is a contrived example.
WITH
x AS
(
SELECT this
FROM THERE
WHERE something is true
),
y AS
(
SELECT this-other-thing
FROM somewhereelse
WHERE something else is true
),
z AS
(
select count(*) k
FROM X
)
SELECT z.k, y.*, x.*
FROM x,y, z
WHERE X.abc = Y.abc
SELECT COUNT(*) as totaloccurs, COUNT(#conditions#) as suboccurs
FROM (#total# as t1)
Put the reused sub-query into a temp table, then select what you need from the temp table.
#EvilTeach:
I've not seen the "with" (probably not implemented in Sybase :-(). I like it: does what you need in one chunk then goes away, with even less cruft than temp tables. Cool.