Redshift Target Table Equijoin Predicate Error with Subquery - sql

I am trying to run an update statement using a subquery to apply logic to the target table before updating. I keep getting the following error (below) even though the target table equijoin is specified in the where clause. Is there something I'm missing? I've also tried converting the subquery into a CTE which results in the same error. The "stg" alias table contains the same amount of rows as the "tgt" so it's not there is a mismatch there.
Error: SQL Error [XX000]: ERROR: Target table must be part of an equijoin predicate
SQL:
update db.target_table as tgt
set
ind = stg.ind_stg
,ts = current_timestamp
from
(
select
load_date
,val_a
,val_b
,stdev.val_a_stdev
,stdev.val_b_stdev
,rec_updated_ts
,case
when (load_date >= 'XXXXX' and load_date <= 'XXXXXX')
or (abs(val_a) >= stdev.val_a_stdev
or abs(val_b) >= stdev.val_b_stdev)
then True else False end as ind
from db.target_table
cross join
(
select
cast(stddev_samp(val_a) as dec(14,2))*2.0 val_a_stdev
,cast(stddev_samp(val_b) as dec(14,2))*2.0 val_b_stdev
from db.target_table
where load_date <= (current_date - 2)
) as stdev
where load_date <= (current_date - 2)
) stg
where stg.load_date = tgt.load_date
However, if I was to wrap the "stg" subquery as a temp table, then ran the same update statement (below), it works. This is perplexing because the original error points towards the target table, but only changing the method of how the subquery is derived fixes the query. Not sure I understand what is going on...
update db.target_table as tgt
set
ind = stg.ind_stg
,ts = current_timestamp
from <SAME STAGE LOGIC> as stg
where stg.load_date = tgt.load_date;

Related

Need to filter target table in SQL merge query

I am using BigQuery SQL to execute a merge query. Here is the query
MERGE `dataset.target_table` AS Target
USING
(
select
*
from
`dataset.source_table` s_data
WHERE
trans_id is not null and user_id is not null
)
AS Source
ON Source.trans_id = Target.trans_id and Target.start_date IN
(
select distinct start_date from `dataset.source_table`
)
WHEN NOT MATCHED BY Target THEN
INSERT (...)
VALUES (...)
WHEN MATCHED and Target.user_id is null THEN
UPDATE SET ...
I am getting an issue with the using a subquery in the ON statement. In Subquery not supported by join predicate
The reason I have this subquery is because I want to filter the Target table before the Merge happens or bigquery throws a OOM exception. The target table is 10billion rows while the source is 200m rows. I don't need the subquery in the ON statement, but it's a hacky way to esentially filter the Target table before the merge happens. Is there some other approach I can take?
I tried the approach here - https://dba.stackexchange.com/questions/30633/merge-a-subset-of-the-target-table utilizing
WITH TARGET AS
(
SELECT *
FROM `dataset.target_table`
WHERE <filter target_table here>
)
MERGE INTO TARGET
...
but it seems this isn't supported by BigQuery and gave a syntax error. How can I filter my Target table before the Merge happens so it doesn't need to load the entire table in memory?
I'm a little confused. Can you just take the start_date from the matching row in source?
MERGE `dataset.target_table` AS Target USING
(select *
from `dataset.source_table` s_data
WHERE trans_id is not null and user_id is not null
) AS Source
ON Source.trans_id = Target.trans_id and
Target.start_date = source.start_date

Updating all the record for a column in a table with value from another table

Hi I want to update all the values of RequestId column of IIL_CHANGE_REQUEST Table with the RequestId of TABLE_NAME_4MINS Table where REQUESTBY column in both tables are same. I am trying to do this in oracle daatabalse(sql developer)
My query:
Update IIL_CHANGE_REQUEST
set REQUESTID=(SELECT TABLE_NAME_4MINS.REQUESTID
FROM TABLE_NAME_4MINS
WHERE IIL_CHANGE_REQUEST.REQUESTBY = TABLE_NAME_4MINS.REQUESTBY)
WHERE EXISTS (SELECT TABLE_NAME_4MINS.REQUESTID
FROM TABLE_NAME_4MINS
WHERE IIL_CHANGE_REQUEST.REQUESTBY = TABLE_NAME_4MINS.REQUESTBY)
But every time I do this I get an error saying:
Error starting at line : 1 in command -
Update IIL_CHANGE_REQUEST
set REQUESTID=(SELECT TABLE_NAME_4MINS.REQUESTID
FROM TABLE_NAME_4MINS
WHERE IIL_CHANGE_REQUEST.REQUESTBY = TABLE_NAME_4MINS.REQUESTBY)
WHERE EXISTS (SELECT TABLE_NAME_4MINS.REQUESTID
FROM TABLE_NAME_4MINS
WHERE IIL_CHANGE_REQUEST.REQUESTBY = TABLE_NAME_4MINS.REQUESTBY)
Error report -
ORA-01427: single-row subquery returns more than one row
Please anyone help how can I do it.
It depends on what you want to do in such cases. If you don't really care, take any value, for example minimum:
update iil_change_request a
set a.requestid = (select min(b.requestid) --> here
from table_name_4mins b
where a.requestby = b.requestby)
where exists (select c.requestid
from table_name_4mins c
where a.requestby = c.requestby);
If that's not what you want, then you'll have to figure out what to do with those "duplicates". Perhaps you'll have to include yet another WHERE condition, or fix data, or ... who knows? I don't, while you should.
You need to find a condition to narrow down returned rows to the only per REQESTSTBY, for example you can replace ... with a column name in the query below to return just first row as per order-by:
MERGE INTO IIL_CHANGE_REQUEST r
USING (
SELECT *
FROM (
SELECT REQUESTBY, REQUESTID
,row_number()over(partition by REQUESTBY order by ...) rn
FROM TABLE_NAME_4MINS
)
where rn=1
) t
ON (r.REQUESTBY = t.REQUESTBY)
WHEN MATCHED THEN UPDATE
set REQUESTID=t.REQUESTID;

Merging 2 partitioned tables BigQuery

I am trying to merge 2 partitioned tables in BigQuery:
'source_t' is a source table. Its partitioned by Ingestion Time with Partition filter –
Required. Pseudo field _PARTITIONTIME is timestamp
'target_t' is a target table partitioned by field 'date' with Partition filter
Required. Field date is date
I want to get data from last partition of source table and merge it to target table. To filter the search task on tagret table I need to use the field 'date' from the data of source table. I wrote a query but editor shows following query error:
Cannot query over table 'MyDataSet.target_t' without a filter over column(s) 'date'
Here is my query:
declare latest default (select date(max(_PARTITIONTIME)) as latest from MyDataSet.source_t where _PARTITIONTIME >= timestamp(date_sub(current_date(),interval 1 day)));
declare first_date default (select min(date) as first_date from MyDataSet.source_t where date(_PARTITIONTIME) = latest);
merge `MyDataSet.target_t` as a
using (select * from `MyDataSet.source_t` where _PARTITIONTIME = latest) as b
on
a.date >= first_date and
a.date = b.date and
a.account_id = b.account_id and
a.campaign_id = b.campaign_id and
a.adset_id = b.adset_id and
a.ad_id = b.ad_id
when matched then update set
a.account_name = b.account_name,
a.campaign_name = b.campaign_name,
a.adset_name = b.adset_name,
a.ad_name = b.ad_name,
a.impressions = b.impressions,
a.clicks = b.clicks,
a.spend = b.spend,
a.date = b.date
when not matched then insert row;
If I input date instead of 'latest' variable ("where _PARTITIONTIME = '2020-10-01') as b") there wont be any error. But I want to filter the source table properly.
And I don't get it how it affects the following 'on' statement and why everything brokes >.<
Could you please help? What is a proper syntax to write such query. And is there any other ways to run such merge without variables?
declare latest timestamp;
Your variable latest is a TIMESTAMP. Making it a DATE type then your query should work.
------ Update --------
The error is complaining about MyDataSet.target_t doesn't have a good filter on date column. Could you try put after on clause a.date = latest (if this is not the right filter, come up with other constant filter)

Merge Query in DB2

I need to update few columns in one table with the very convoluted calculation.
I'm not good enough in SQL so I tried to use "with" clause in combination with update, but It threw error.
Then I found a post online which suggested to use MERGE so I came up with Merge query. But that one was also throwing an error.
So I removed all other column and updating only one column to remove complexity, but no avail still errors
Below is my query, select query inside working perfectly fine.
Please suggest.
MERGE INTO TABLE_1 AS O
USING (
SELECT ((TO_NUMBER(TABLE_3.Total_Whsle_Price)-TO_NUMBER(TABLE_2.OPT_BASE_WHSLE)) - ((TO_NUMBER(TABLE_3.Total_Whsle_Price)-TO_NUMBER(TABLE_2.OPT_BASE_WHSLE))*TO_NUMBER(TABLE_1.AUC_MILEAGE))/100000 ) as CORRECT_FLOOR_PRICE
FROM TABLE_1, TABLE_2,TABLE_3
WHERE TABLE_2.Primary_ID= TABLE_1.Primary_ID
AND TABLE_2.option_code = 'FSDS'
AND TABLE_1.FLOOR_PRICE <> '0.00'
and TABLE_3.Primary_ID=TABLE_1.Primary_ID
and TABLE_3.Primary_ID=TABLE_2.Primary_ID
) AS CORRECT
ON(
O.Primary_ID = CORRECT.Primary_ID
)
WHEN MATCHED THEN
UPDATE
set O.FLOOR_PRICE =CORRECT.CORRECT_FLOOR_PRICE
Error is
An error occurred when executing the SQL command:
MERGE INTO ........
DB2 SQL Error: SQLCODE=-199, SQLSTATE=42601, SQLERRMC=SELECT;VALUES, DRIVER=3.61.75 [SQL State=42601, DB Errorcode=-199]
Try this instead, I think you forgot your identifier in your select statement because after the "ON" statement "CORRECT.Primary_ID" doesn't associate to anything.
MERGE INTO TABLE_1 as O
USING (
SELECT ((TO_NUMBER(TABLE_3.Total_Whsle_Price)-TO_NUMBER
(TABLE_2.OPT_BASE_WHSLE)) - ((TO_NUMBER(TABLE_3.Total_Whsle_Price)
-TO_NUMBER(TABLE_2.OPT_BASE_WHSLE))*TO_NUMBER
(TABLE_1.AUC_MILEAGE))/100000 ) as CORRECT_FLOOR_PRICE,
TABLE_1.Primary_ID AS Primary_ID
FROM
TABLE_1, TABLE_2,TABLE_3
WHERE TABLE_2.Primary_ID = TABLE_1.Primary_ID
AND TABLE_2.option_code = 'FSDS'
AND TABLE_1.FLOOR_PRICE <> '0.00'
AND TABLE_3.Primary_ID=TABLE_1.Primary_ID
AND TABLE_3.Primary_ID=TABLE_2.Primary_ID
) AS CORRECT
ON(
O.Primary_ID = CORRECT.Primary_ID
)
WHEN MATCHED THEN
UPDATE
set O.FLOOR_PRICE = CORRECT.CORRECT_FLOOR_PRICE

Oracle - How to use merge to update a column based on the values from other table and columns

I would like to update the values in closed_date column based on the values comparison from other columns and other table. I used Oracle merge into statement. But it gave me an error:
Error: ORA-00969: missing ON keyword
I am not sure what goes wrong. Do I miss anything? Below is my script:
MERGE INTO PR_DMN dmn
USING (select alg.PR_DMN_ID, alg.PR_ACTIVITY_ID, alg.ACTIVITY_TS from PR_ACTIVITY_LOG) alg
ON dmn.PR_DMN_ID = alg.PR_DMN_ID
-- update
WHEN MATCHED THEN
UPDATE SET dmn.CLOSED_DATE =
(CASE
WHEN alg.PR_ACTIVITY_ID IN ('10009', '10010', '10011', '10013') THEN alg.ACTIVITY_TS
WHEN alg.PR_ACTIVITY_ID = '10005' AND dmn.CONT_RESP_TS <= dmn.CONT_RESP_DUE_TS THEN dmn.CONT_RESP_TS
WHEN alg.PR_ACTIVITY_ID = '10008' AND dmn.CORR_RESP_TS <= dmn.CORR_RESP_DUE_TS THEN dmn.CORR_RESP_TS
ELSE dmn.CLOSED_DATE
END)
You have two errors, as you can see with a simple example. Firstly the on clause needs to be wrapped in parenthesis. Secondly, you can't reference the alias of the sub-select in the using clause within that sub-query.
If I set up a simple example using your table names as follows:
create table pr_dmn as
select level as a, sysdate as b
from dual
connect by level <= 10;
Table created.
create table PR_ACTIVITY_LOG as
select level as a, sysdate as b
from dual
connect by level <= 20;
Table created.
Then execute the correct query it should work:
merge into pr_dmn dmn
using (select a, b from pr_activity_log) alg -- no alg. inside the sub-query
on (dmn.a = alg.a) -- wrapped in parenthesis
when matched then
update set dmn.b = alg.b
;
10 rows merged.
I always find PSOUG a good reference for things like this, though the documentation has some good examples as well.