PostgreSQL:how to update rows in CTE - sql

am running PostgreSQL 9.2.
below given is a sample of my huge and uglyquery
with cte as(
select ....... from aTable
),cte1 as (
select ..... from bTable inner join cte using(anID)
),update_cte as(
update cte set aField=(select somthing from cte1)
)
select * from cte
i need to create a view with the final result.
while executing the above am getting an error which is below.
ERROR: relation "cte" does not exist
I know am doing something bad.hope you can understand what am trying to achieve from the above query.
So please suggest any alternative method for it.
Replies are much appreciated.
Note : the actual query

with cte as(
select ....... from aTable
),update_cte as(
update cte set aField=(select somthing from cte1)
)
You can't do that.
An UPDATE may not reference a CTE term in PostgreSQL, as CTEs are materialized. They aren't just views over the underlying data. (That's sometimes really annoying, but that's how it is).
You can:
CREATE TEMPORARY VIEW someview AS SELECT ... FROM atable;
UPDATE someview SET afield = ...
if you want; that'll work on newer PostgreSQL versions that support automatically updatable views. I think 9.2 does.
Otherwise, I think you want something like:
WITH cte1 as (
select ..... from bTable inner join cte using(anID)
)
update aTable
set aField=(select somthing from cte1)
WHERE ... where clause from cte ...
RETURNING *;
but really, please don't call your CTE terms cte, cte1, etc. Give them useful, descriptive names that tell you what they are. It's like programs full of variables named a through x ... the next person who has to maintain your code, or anyone you ask for help, will not like it.

Related

Using nested query twice within one query - for FROM and WHERE

I am trying to figure out why the following Microsoft SQL code does not work. I simplified the query as it is quite complex. Basically the part that is not working is the second nested subquery (line FROM a) - I get an error: Invalid object name 'a'.
I would appreciate any advice on why it is not working and how I could make it work. Some background sources on why is it not working would also be helpful, as I struggle to find any information on limitations of nested queries beyond some basics.
SELECT *
FROM (
SELECT ... FROM ...
) a
WHERE x IN(
SELECT x
FROM a
WHERE v1=v2)
I managed to solve my problem thanks to the suggestion in the comments to use CTE.
So I transformed it into:
WITH CTE_1
AS
(
SELECT ... FROM ...
)
SELECT * FROM CTE_1
WHERE x IN(
SELECT x
FROM CTE_1
WHERE v1=v2)

BigQuery referencing subquery under WITH clause in WHERE clause

Basically I want to reference the ListOfIds subquery defined in the WITH clause directly as a single column table. As an example, I want to achieve something like the following.
WITH
ListOfIds AS (
SELECT
Id
FROM
...)
SELECT
*
FROM
...
WHERE
Id IN ListOfIds
The above syntax results in an error of ListOfIds is not defined on the line Id IN ListOfIds
So far the closest I can get to is the following, and I don't like it for its somewhat complicated and redundant syntax.
WITH
ListOfIds AS (
SELECT
Id
FROM
...)
SELECT
*
FROM
...
WHERE
Id IN (
SELECT
Id
FROM
ListOfIds)
Thanks in advance for any help or advice.
Firstly a note.
You probably don't want to do this.
CTEs (the WITH query) is a bit counterintuitive for people who normally code because it feels like a variable but it is not.
What actually happens is that you run the query many times to evaluate it, resulting in poor performance and extra $$ spent.
I recommend you replace this for a simple JOIN, it will achieve the same thing and generally be just way better.
Basically your query would be like:
WITH list_of_ids AS (
SELECT id FROM table_with_ids
)
SELECT main_table.*
FROM main_table
JOIN list_of_ids
ON main_table.id = list_of_ids.id
I think it is pretty clean syntax and solves your problem.
Let me know if there is something I am missing and I can add to this.
Addition to what Francesco says, if you really want to use it as a variable, actually it is also possible and probably not expensive at all.
DECLARE ListOfIds ARRAY<INT64> DEFAULT (SELECT ARRAY_AGG(Id) FROM ...);
SELECT
*
FROM
...
WHERE
Id IN UNNEST(ListOfIds)
Below is for BigQuery Standard SQL
#standardSQL
WITH ListOfIds AS (
SELECT ARRAY_AGG(Id) ids
FROM ...
)
SELECT * EXCEPT(ids)
FROM ...
,ListOfIds
WHERE id IN UNNEST(ListOfIds.ids)
[Super] Simplified example for testing/playing with above is :
#standardSQL
WITH ListOfIds AS (
SELECT ARRAY_AGG(Id) ids
FROM UNNEST([1, 2, 3, 4, 5]) id
)
SELECT * EXCEPT(ids)
FROM UNNEST([1, 3, 5, 7, 9]) id
,ListOfIds
WHERE id IN UNNEST(ids)
with output
Row id
1 1
2 3
3 5

How to reuse a sub query in sql?

I have query like the following
select columns
from (select columns1
from result_set
where condition_common and condition1) as subset1
join
(select columns2
from result_set
where condition_common and condition2) as subset2
on subset1.somekey = subset2.somekey
I want to somehow reuse
select columns
from result_set
where condition_common
I have oversimplified the above query, but the above select in reality is huge and complicated. I dont want to have the burden of making sure both are in sync
I dont have any means of programmatically reusing it. T-SQL is ruled out. I can only write simple queries. This is an app limitation.
Is there a way to reuse same subquery, in a single statement
Use a Common Table Expression (CTE) if you're using SQL Server 2005+:
with cte as (
select columns
from result_set
where condition_common
)
select columns
from cte as subset1
join
cte as subset2
on subset1.somekey = subset2.somekey
where otherconditions

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

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.

Using output from "with as" few times

I can't use t from
with t as (
select row_number() OVER (partition by ID ORDER BY id) as numb, *
from my_table
where id= 6
)
select top 2 from t # it works
select top 2 from t # here I get error Invalid object name 't'.
Is there any tip to use t more than on time?
You cannot do this. CTEs can only be used in one statement (though you can use it multiple times within one statement.
Take a look at this article. Snippit:
Once a CTE is defined, it can be
referenced multiple times by the first
query that follows it.
And from their documentation:
A common table expression (CTE) can be
thought of as a temporary result set
that is defined within the execution
scope of a single SELECT, INSERT,
UPDATE, DELETE, or CREATE VIEW
statement.
Emphasis on, "scope of a single SELECT, INSERT, UPDATE, DELETE, or CREATE VIEW statement."
Is there any tip to use t more than on time?
Sure, if you are doing this in a stored proc, just dump it into a #temp table. At the end of the stored proc, the #temp table disappears.
with t as (
select row_number() OVER (partition by ID ORDER BY id) as numb, *
from my_table
where id= 6
)
select * into #tmp from t
select top 2 from #tmp -- good
select top 2 from #tmp -- good also
Outside of SP, just make sure you drop the #table before you attempt to create it again, otherwise the next select ..into #name will error out with #name already exists
You can use a CTE only in a single query that follows the CTE. You can however make the query that follows as complicated as you wish.
In your example, you might consider a union between the 2 selects depending on precisely what you want. The code you gave isn't descriptive enough for me to suggest any other variants.