SQL: Unable to use 'with as' to save selected result - sql

I have an inner join result that I want to save it by using with as but received an error. I'm using snowflake.
My code:
with t as (select *
from
(select ID, PRICE from DB.TABLE1
WHERE PRICE IS NOT NULL and ID = '1111') A
inner join
(select ID, BID, ACCEPTED from DB.TABLE2
WHERE BID IS NOT NULL and ID = '1111') B
ON A.ID = B.ID);
Error: SQL compilation error: syntax error line 8 at position 25 unexpected ';'.
If I only run the inner join
select *
from
(select ID, PRICE from DB.TABLE1
WHERE PRICE IS NOT NULL and ID = '1111') A
inner join
(select ID, BID, ACCEPTED from DB.TABLE2
WHERE BID IS NOT NULL and ID = '1111') B
ON A.ID = B.ID
I got this result
ID, PRICE,ID,BIDS,ACCEPTED
1111,180,1111,200,FALSE
1111,180,1111,180,FALSE
1111,180,1111,180,FALSE
1111,180,1111,100,TRUE
Any idea why I got the error message?

You use with to essentially create an alias (called a common table expression) for the query that can then be used in that specific query. All you've done is create the alias without using it. You need something like:
with t as (select *
from
(select ID, PRICE from DB.TABLE1
WHERE PRICE IS NOT NULL and ID = '1111') A
inner join
(select ID, BID, ACCEPTED from DB.TABLE2
WHERE BID IS NOT NULL and ID = '1111') B
ON A.ID = B.ID)
select * from t
Although obviously you'd usually do more complex work than that or else you'd just write the base query without using with

WITH is syntax used to introduced a common table expression. This is an expression used within a single query. It is a lot like a subquery in the FROM clause, except that it can be referenced more than once.
So a correct usage would be:
with t as (
select . . .
)
select count(*)
from t;
In other words, you need to follow the with with something that uses the CTE. Otherwise, you want to store the results in a real table -- temporary or otherwise.

To use CTE, join should be made after creating the tables.
with t as
(select ID, PRICE from DB.TABLE1
WHERE PRICE IS NOT NULL and ID = '1111') ,
t1 as
(select ID, BID, ACCEPTED from DB.TABLE2
WHERE BID IS NOT NULL and ID = '1111')
select *
from t
inner join
t1
on t.ID = t1.ID;

Related

how to define table name and conduct multiple table selection

I need to use multiple table selections in a query in SQL. But how to reference a table selected within a query?
for example: (pseudo code)
create table C as
select distinct id, product_code
from (
select distinct id, product_code
from A where dt = '2019-06-01'
)
inner join B on (select distinct id, product_code
from A where dt='2019-06-01').id = B.id;
the code above might be wrong, but the point is that the table A could not be used directly since it's too large and it has to be specified that dt is some specific value. (so I need to select something from A for double times above). And I need to inner join the smaller A' with some other table B.
Is it possible, say, "define" that table A_ = select distinct blabla...from A ... and then join A_ with B within a query?
thanks,
You just want a table alias:
select distinct id, product_code
from (select distinct id, product_code
from table_A
where dt = '2019-06-01'
) a inner join
table_B b
on a.id = B.id;

How to find unmatched records in a single table?

I'm scraping a log file for transaction records that I am inserting into a table that will be used for several mining tasks. Each record has (among other things) an ID and a transaction type, either request or response. A request/response pair will have the same ID.
One of my tasks is to find all of the requests that do not have a corresponding response. I thought about joining the table to itself, where A.ID = B.ID AND A.type = 'req' and B.type = 'res', but that gives me the opposite of what I need.
Since the IDs will always occur either once or twice, is there a query that would select ID where there is only one occurrence of that ID in the table?
This is a very common type of query. You can try aggregating over the ID values in your table using GROUP BY, then retaining those ID which appear only once.
SELECT ID
FROM yourTable
GROUP BY ID
HAVING COUNT(*) = 1
If you also want to return the entire records for those ID occurring only once, you could try this:
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT ID FROM yourTable GROUP BY ID HAVING COUNT(*) = 1
) t2
ON t1.ID = t2.ID
The straight-forward way is NOT IN:
select *
from mytable
where type = 'req'
and id not in (select id from mytable where type = 'res');
You can write about the same with NOT EXISTS, but the query becomes slightly less readable:
select *
from mytable req
where type = 'req'
and not exists (select * from mytable res where type = 'res' and res.id = req.id);
And then there are forms of aggregation you can use, e.g.:
select *
from mytable
where type = 'req'
and id in
(
select id
from mytable
group by id
having count(case when type = 'res' then 1 end) = 0
);
This will give you the ones that have Request but not respose
SELECT *
FROM your_table A LEFT OUTER JOIN
your_table B ON A.ID = B.ID
AND A.type = 'req' and B.type = 'res'
WHERE B.ID IS NULL

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

Written a subquery that can return more than one field without using the Exists

The query below is supposed to pull records for fields with the max date.
I am getting an error
You have written a subquery that can return more than one field without using EXISTS reserved word in the Main query's FROM clause. Revise the SELECT statement of the subquery to request only one column.
Code:
SELECT *
FROM TableName
WHERE (((([Project_Name], [Date])) IN (SELECT Project_Name, MAX(Date)
FROM TableName
GROUP BY Project)));
Your probably thinking of a nested subquery used as a table, like the below:
select a.*, b.1, b.2
from FirstTable A
join (Select Id, firstcolumn as 1, secondcolumn as 2
from SecondTable) B on b.ID = a.ID
Works pretty much like a regular join except you are using a subquery. Hope that helps,
SELECT A.*
FROM TableName A
INNER JOIN (select Project_Name, max(Date) MaxDate
from TableName
group by Project) B
ON A.[Project_Name] = B.[Project_Name]
AND A.[Date] = B.MaxDate
A version using EXISTS() looks like this:
SELECT *
FROM TableName AS A
WHERE EXISTS(
SELECT * FROM (
SELECT B.Project_Name, MAX( B.Date ) AS MaxDate
FROM TableName AS B
GROUP BY B.Project_Name ) AS C
WHERE C.Project_Name = A.Project_Name AND C.MaxDate = A.Date
);
Although I have the feeling this will have poorer performance than a JOIN because the GROUP BY statement might have to be executed for each record and each call to the EXISTS() function...

query optimization with condition

I want to optimze the follwing query, to not use subquery to get max value:
select c.ida2a2 from table1 m, table2 c
where c.ida3a5 = m.ida2a2
and (c.createstampa2 < (select max(cc.createstampa2)
from table2 cc where cc.ida3a5 = c.ida3a5));
Any idea? Please let me know if you want to get more info.
This may be a more efficient way to write the query:
select c.ida2a2
from table1 m join
(select c.*, MAX(createstampa2) over (partition by ida3a5) as maxcs
from table2 c
) c
on c.ida3a5 = m.ida2a2
where c.createstampa2 < maxcs
I'm pretty sure Oracle optimizes this correctly (filtering the rows before the join). If you wanted to be clearer:
select c.ida2a2
from table1 m join
(select c.*
from (select c.*, MAX(createstampa2) over (partition by ida3a5) as maxcs
from table2 c
) c
where c.createstamp2 < c.maxcs
) c
on c.ida3a5 = m.ida2a2