Using A CTE with a left join - sql

I have an exiting query with a structure:
With As MainQuery(.....)
As Sub 1 (.....)
As Sub 2 (.....)
As Sub 3 (.....)
select.....
I now need to join the results from this query to another query I have, so I want to left join it to the other query..
like this:
left join (
select * from (
With As MainQuery(.....)
As Sub 1 (.....)
As Sub 2 (.....)
As Sub 3 (.....)
select.....) as results
I keep getting errors. not sure if this is possible or which other methods can I use.
Thank you

I can't think of any exceptions as to why this won't work. But all you have to do is move your CTE's to the top of the main query.
In this particular example, since your sub-query is not correlated (the subquery is not accessing any fields in the outside query, it's simply returning a dataset). Then you can just move the CTE's to the top, like this:
-- Generate list of numbers 1-9, then select top 5 randomly
WITH c1 AS (SELECT x.x FROM (VALUES(1),(1),(1)) x(x))
, c2(x) AS (SELECT 1 FROM c1 x CROSS JOIN c1 y)
, c3(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY c2.x) FROM c2)
SELECT TOP(5) x.n
FROM c3 x
ORDER BY NEWID();
-- All numbers 1-9
SELECT x.n
FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9)) x(n)
Say I have these two queries. I want to LEFT JOIN my query with the CTE's into my second query. So that way I have all numbers 1-9, on the left, and then I can see which numbers are missing from the right.
Just move your SELECT statement to the LEFT JOIN subquery, and you can still reference your CTE's:
WITH c1 AS (SELECT x.x FROM (VALUES(1),(1),(1)) x(x))
, c2(x) AS (SELECT 1 FROM c1 x CROSS JOIN c1 y)
, c3(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY c2.x) FROM c2)
SELECT x.n, z.n
FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9)) x(n)
LEFT JOIN (
SELECT TOP(5) x.n
FROM c3 x
ORDER BY NEWID()
) z ON z.n = x.n
Now, if you were trying to use something that references outside the subquery, like a correlated subquery in the SELECT list, or an OUTER/CROSS APPLY or maybe an EXISTS() clause, that's different. But in this case, if it's not correlated, then simply moving it to the top should work just fine.

Related

"Duplicating" entries SQL

I have a column that looks like
a
b
c
and I think I can select using some sort of a window function to get
a 1
a 2
b 1
b 2
c 1
c 2
but can't seem to find something suitable.
I know you can do this using a union but would prefer using a window function if it exists.
Considering you just want 2 rows, I would just CROSS JOIN to a VALUES table construct with the values 1 and 2 in it:
SELECT YT.YourColumn,
V.I
FROM dbo.YourTable YT
CROSS JOIN (VALUES(1),(2))V(I);
select t.myColumn, x.N
from myTable t
CROSS JOIN
(SELECT TOP (2)
ROW_NUMBER() OVER (ORDER BY t1.Object_ID) AS N
FROM Master.sys.All_Columns t1
CROSS JOIN Master.sys.All_Columns t2) x

PostgreSQL: Error in left join

I am trying to join my master table to some sub-tables in PostgreSQL in a single select query. I am getting a syntax error and I have the feeling I am making a terrible mistake or doing something which is not allowed. The code:
Select
id,
length,
other_stuff
from my_table tbl1
Left join
(
Select
id,
height
from my_table2 tbl2) tbl2 using (id)
left join
-- I get syntax error here
(
With a as (select id from some_table),
b as (Select value from other_table)
Select id, value from a, b) tbl3 using (id)
order by tbl1.id
Can we use WITH clause in left joins sub or nested queries and Is there a better way to do this?
UPDATE1
Well, I would like to add some more details. I have three select queries like this (having unique ID) and I want to join them based on ID.
Query1:
With a as (Select id, my_other records... from postgres_table1)
b as (select id, my_records... from postgres_table2)
c as (select id, my_record.. from postgres_table3, b)
Select
id,
my_records
from a left join c on some_condtion_with_a
order by 1
Second query:
Select
id, my_records
from
(
multiple_sub_queries_by_getting_records_from_c
)
Third Query:
With d as (select id, records.. from b),
e as (select id, records.. from d),
f as (select id, records.. from e)
select
id,
records..
from f
I tried to join them using left join. The first two queries were joined successfully. While, joining third query I got the syntax error. Maybe, I am complicating things thus I asked is there a better way to do it.
You are over complicating things. There is no need to use a derived table to outer join my_table2. And there is no need for a CTE plus a derived table to join the tbl3 alias:
Select id,
length,
other_stuff
from my_table tbl1
Left join my_table2 tbl2 using (id)
left join (
select st.id, ot.value
from some_table st
cross join other_table ot
) tbl3 using (id)
order by tbl1.id;
This assumes that the cross join you create with Select id, value from a, b is intended.
Not tested, but I think you need this. try:
with a as (select id from some_table),
b as (Select value from other_table)
Select
id,
length,
other_stuff
from my_table tbl1
Left join
(
Select
id,
height
from my_table2 tbl2
)
tbl2 using (id)
left join
(
Select id, value from a, b
)
tbl3 using (id)
order by tbl1.id
I've only ever seen/used WITH in the following format:
WITH
temptablename(columns) as (query),
temptablename2(columns) as (query),
...
temptablenameX(columns) as (query)
SELECT ...
i.e. they come first
You'll probably find it easier to write queries if you use indentation to describe nesting levels. I like to make my SELECT FROM WHERE GROUPBY ORDERBY at one indent level, and then tablename INNER JOIN ON etc more indented:
SELECT
column
FROM
table
INNER JOIN
(
SELECT subcolumn FROM subtable WHERE subclause
) myalias
ON
table.id = myalias.whatever
WHERE
blah
Organising your indents every time you nest down a layer really helps. By making everything that is "a table or a block of data like a table (i.e. a subquery)" indented the same amount you can easily see the notional order that the DB should retrieve
Move your WITHs to the top of the statement, you will still use the alias names in place in the sub sub query of course
Looking at your query, there isn't much point in your subqueries.. You don't do any grouping or particularly complex processing of the data, you just select an ID and another column and then join it in. Your query will be simpler if you don't do this:
SELECT
column
FROM
table
INNER JOIN
(
SELECT subcolumn FROM subtable WHERE subclause
) myalias
ON
table.id = myalias.whatever
WHERE
blah
Instead, do this:
SELECT
column
FROM
table
INNER JOIN
subtable
ON
table.id = subtable.id
WHERE
blah
Re your updated requirements, following the same pattern.
look for --my comments
With a as (Select id, my_other records... from postgres_table1)
b as (select id, my_records... from postgres_table2)
c as (select id, my_record.. from postgres_table3, b)
d as (select id, records.. from b),
e as (select id, records.. from d),
f as (select id, records.. from e)
SELECT * FROM
(
--your first
Select
id,
my_records
from a left join c on some_condtion_with_a
) Q1
LEFT OUTER JOIN
(
--your second
Select
id, my_records
from
(
multiple_sub_queries_by_getting_records_from_c
)
) Q2
ON Q1.XXXX = Q2.XXXX --fill this in !!!!!!!!!!!!!!!!!!!
LEFT OUTER JOIN
(
--your third
select
id,
records..
from f
) Q3
ON QX.XXXXX = Q3.XXXX --fill this in !!!!!!!!!!!!!!!!!!!
It'll work, but it might not be the prettiest or most necessary SQL arrangement. As both i and HWNN have said, you can rewrite a lot of these queries where you're just doing some simple selecting in your WITH.. But likely that theyre simple enough that the database optimizer can also see this and rerwite the query for you when it runs it
Just remember to code clearly, and lay your indentation out nicely to stop it tunring into a massive, unmaintainable, undebuggable spaghetti mess

sql select query IN Clause returns nothing

Is it possible to get any value from the parameters passed inside IN clause where 1 value returns nothing.
Example:
select id, translation
from <table>
where id in (1,2,36)
and (locale_id='EN' )
If id 2 has no values in table, is it possible to return NULL in place of no values at all.
Currently it returns only 2 values.
try this:
with cte as (
select *
from (values (1),(2),(36) ) v(v)
)
select *
from cte
left join table1 t1 on t1.id=cte.v and (t1.locale_id='EN' )
you'll get at least on record per id
cte generates 3 records, each with one value v i prefer the syntax with cte over the following version (which should do the same)
select *
from (values (1),(2),(36)) v(v)
left join table1 t1 on t1.id=v.v and (t1.locale_id='EN' )
the left join well read yourself : http://www.w3schools.com/sql/sql_join_left.asp

In sql, can you join to a select statement that references the outer tables in other joins?

What I want to do is to transform the following sql
SELECT X
FROM Y LEFT JOIN Z ON Y.Id=Z.id
WHERE Y.Fld='P'
into
SELECT Y
FROM Y LEFT JOIN (SELECT TOP 1 Id FROM Z WHERE Z.Id=Y.Id ORDER BY Z.PrimaryKey DESC) ON 1=1
WHERE Y.Fld='P'
The reason I want to do this is because Z has multiple rows that can be joined to Y, that are not unique in a distinguishable way, other than that the one we need is the latest one, and we only need that one record. Is this possible? I tried it but mssql complained that I cannot reference Y.Id from within the sub query.
How about a CTE approach:
;WITH CTE
AS
(
SELECT Id,
PrimaryKey,
ROW_NUMBER() OVER (PARTITION BY Id, ORDER BY Primarykey Desc) AS RN
FROM Z
)
SELECT X
FROM Y
LEFT JOIN CTE
ON CTE.ID = Y.ID
WHERE CTE.RN = 1

SQL Server ROW_NUMBER Left Join + when you don't know column names

I'm writing a page that will create a query (for non-db users) and it create the query and run it returning the results for them.
I am using row_number to handle custom pagination.
How do I do a left join and a row_number in a subquery when I don't know the specific columns I need to return. I tried to use * but I get an error that
The column '' was specified multiple times
Here is the query I tried:
SELECT * FROM
(SELECT ROW_NUMBER() OVER (ORDER BY Test) AS ROW_NUMBER, *
FROM table1 a
LEFT JOIN table2 b
ON a.ID = b.ID) x
WHERE ROW_NUMBER BETWEEN 1 AND 50
Your query is going to fail in SQL Server regardless of the row_number() call. The * returns all columns, including a.id and b.id. These both have the same name. This is fine for a query, but for a subquery, all columns need distinct names.
You can use row_number() for an arbitrary ordering by using a "subquery with constant" in the order by clause:
SELECT * FROM
(SELECT ROW_NUMBER() OVER (ORDER BY (select NULL)) AS ROW_NUMBER, *
FROM table1 a
LEFT JOIN table2 b
ON a.ID = b.ID) x
WHERE ROW_NUMBER BETWEEN 1 AND 50 ;
This removes the dependency on the underlying column name (assuming none are named ROW_NUMBER).
Try this sql. It should work.
SELECT * FROM
(SELECT ROW_NUMBER() OVER (ORDER BY a.Test) AS ROW_NUMBER, a.*,b.*
FROM table1 a
LEFT JOIN table2 b
ON a.ID = b.ID) x
WHERE ROW_NUMBER BETWEEN 1 AND 50