Unable to get a stable set of rows in the source tables - sql

I am facing this issue, can someone help to validate this merge statement?
MERGE INTO WC_FNHLDNG_D T1
USING (SELECT distinct ROW_WID, CONTACT_WID
FROM W_ASSET_D
WHERE X_TYPE_CD='Fin Account')T2
ON (T1.ASSET_WID=T2.ROW_WID)
WHEN MATCHED THEN UPDATE
SET T1.CONTACT_WID=T2.CONTACT_WID;

Acquire locks on WC_FNHLDNG_D and W_ASSET_D before attempting the MERGE operation.

The rule of merge is that there must be no more than one row in the USING subquery which matches a row in the target table.
Your subquery is this:
SELECT distinct ROW_WID, CONTACT_WID
FROM W_ASSET_D
So if there is more than one different CONTACT_WID for a given ROW_WID it will return multiple rows for the ROW_WID. The DISTINCT clause won't help, because the CONTACT_WID are different.
The fact that your statement hurls ORA-30926 suggests this is the state of your data. Oracle doesn't know which W_ASSET_D.CONTACT_WID is the right one to merge into WC_FNHLDNG_D so it gives up. The solution to rewrite the USING subquery so it returns only one CONTACT_WID per ROW_WID.
You should have some additional business rules you can add in a WHERE clause. But as a last resort you can use an aggregating function, e.g.
USING (SELECT ROW_WID, max( CONTACT_WID) as CONTACT_WID
FROM W_ASSET_D
WHERE X_TYPE_CD='Fin Account'
group by ROW_WID
)T2
This is better than choosing a random CONTACT_WID but not by much :)

Related

PostgreSQL: Inserting into one table then updating another using the same subquery, within the same single query

I have a fairly intricate query and I am finding it difficult to create the result of updating two different tables from the same subquery in the FROM. The difficulty I am facing is suggesting I have attempted the incorrect flow:
Below is an extremely simplified version of the script I have working for updating table1 from the subquery:
UPDATE
table1
SET
columnX= subquery.column2
FROM
(
SELECT column1, column2, column2
FROM table2
) AS subquery
WHERE subquery.column1 = table1.column1;
Now I need to bring a third table (table3) into the mix and map table2(subquery).column2 to a value on INSERT.
I cannot do this using a second query which would be ideal as the subquery generates UUID's that must persist across the table1.columnX and table3.column1.
Can I include the INSERT within the subquery whilst still returning the same subquery table?
INSERT...RETURNING uuid_column_name may be the magic you need in your subquery.
https://www.postgresql.org/docs/13/sql-insert.html

is there an alternative to query with DELETE snowflake SQL statement with CTE?

On snowflake, is there an alternative to query with DELETE SQL statement with CTE? seems it is not possible.
with t as (
select * from "SNOWFLAKE_SAMPLE_DATA"."TPCDS_SF100TCL"."CALL_CENTER"
), p as (select t.CC_REC_END_DATE, t.CC_CALL_CENTER_ID , t.CC_REC_START_DATE from t where 1=1 AND t.CC_REC_START_DATE > '2000-01-01')
delete from p
For example: if we use a select, we got some results.
but if I use a delete. It shows a syntax error
The problem with this thinking is that SELECT returns some values, that might, or might not be, matching individual records in your table. In principle, they might return even combinations of values from multiple tables, multiple rows, or no rows at all even. What would you want DELETE to do then?
So, for DELETE, you need to specify which rows in the table you're operating on are deleted. You can do it with a simple WHERE clause, or with a USING clause.
If you want CTEs with DELETE, the closest would be to use USING, put a subquery there, and join its result with the table. In many cases that's a very useful approach, but it is causing a join, which has a performance impact. Example:
delete from CALL_CENTER t
using (
select cc_call_center_sk from CALL_CENTER
where 1=1 AND t.CC_REC_START_DATE > '2000-01-01'
) AS sub
where sub.cc_call_center_sk = t.cc_call_center_sk.
But again, for your query it doesn't make much sense, and what #cddt wrote is probably your best bet.
The expected outcome from the question is not clear, so this is my best interpretation of it.
It seems like you want to delete records from the table SNOWFLAKE_SAMPLE_DATA.TPCDS_SF100TCL.CALL_CENTER where the field CC_REC_START_DATE is greater than 2000-01-01. If that's what you want to achieve, then you don't need a CTE at all.
DELETE FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF100TCL.CALL_CENTER t
WHERE t.CC_REC_START_DATE > '2000-01-01'

Using Distinct in Aggregate Select query

I am using oracle DB. I have a Aggregated script. We found that some of the rows in the table are repeated, unwanted and hence, is not supposed to be added in the sum.
now suppose i use Distinct command just after the select statement, will distinct command applied before aggregation or after it.
If you use SELECT DISTINCT, then the result set will have no duplicate rows.
If you use SELECT COUNT(DISTINCT), then the count will only count distinct values.
If you are thinking of using SUM(DISTINCT) (or DISTINCT with any other aggregation function) be warned. I have never used it (except perhaps as a demonstration), and I have written a fair number of queries.
You really need to solve the problem at the source. For instance, if accounts are being repeated, then SUM(DISTINCT) does not distinguish between accounts, only by the values assigned to the account. You need to get the logic right.
when you say that you have repeated rows - you must have a clear idea of uniqueness for the combination of some specific columns.
If you expect that certain column combinations are unique within specified groups yo can detect the groups deviating from that using queries following the pattern below.
select <your group by columns>
from <your table name>
group by <your group by predicate>
having (max(A)!=min(A) or max(B)!=min(B) or max(C)!=min(C))
Then you have to decide what to do with the problem. I would suggest cleaning up and adding unique constraints to the table.
The aggregate query you mention would run successfully for the rows in your table not having duplicate values for the combination of columns that needs to be unique. Using my example you could get the aggregates for that part of your data using the inverted having predicate.
It would be something like this
select <your aggregate functions, counts, sums, averages and so on>
from <your table name>
group by <your group by predicate>
having (max(A)=min(A) and max(B)=min(B) and max(C)=min(C))
If you must include the groups breaking uniqueness expectations you must somehow do a qualified selection of which of the variants in the group to use - you could for example go for the last one or the first one if one of your columns should happen to express something about when the row was created.

Combining Queries into one and iterate for multiple unique identifiers

I am trying to see if there is a way to combine CTE query and the Update query into one query. Also, I need to iterate the following query for multiple "AttributeId", when I try to put multiple AttributeID's in "in clause" it does not give me the result I want. Is there a better way of writing this query and instead of repeating the same query over and over again for different attribute ID - is the a way to write it like we write For Each loop? Thank you very much for your help!
Yes you can update a table from a CTE result.
I've already done that in the past and I've built this SQL Fiddle as an example if you want to see it live.
So, you need to use the UPDATE statement combined with the FROM clause and specify the "join" condition in the WHERE, like this:
;WITH CTE
AS
(
-- Fill the data you want to update
SELECT personID, COUNT(1) AS count
FROM person_movies
GROUP BY personID
)
-- Update statement. You can use SELECT, UPDATE, INSERT or DELETE
UPDATE persons
-- Specify the columns you want to update
SET moviecount = CTE.count
-- Specify the source, in this case is from the CTE
FROM CTE
-- How can we "link" the results in both tables? Specify it here
WHERE persons.personID = CTE.personID

SQL error ORA 01427

I am trying to update one of the columns in my table by collecting the values from another table in the data store using this query
UPDATE tablename PT
SET DID = (select distinct(did) from datastore.get_dept_alias
where upper(ltrim(rtrim(deptalias))) = upper(ltrim(rtrim(PT."Dept Descr")))
AND cid = PT.CID)
Note: Both the column names in the table are the same as entered
I get ORA 01427 error. Any idea about the issue?
I am trying to understand the other posts of this ORA error
As you can see here
SQL Error: ORA-01427: single-row subquery returns more than one row
This means that your sub-query
select distinct(did) from datastore.get_dept_alias
where upper(ltrim(rtrim(deptalias))) = upper(ltrim(rtrim(PT."Dept Descr")))
AND cid = PT.CID)
is returning more than one row.
So, are you sure that distinct (did) is unique? Looks like it's not. I don't recommend using where rownum = 1 because you don't know which one of the values will be used to update; unless you use ORDER BY.
Your getting this error because your select statement can return more than one result. You can not update a single cell with a query that can potentially return more than one result.
A common approach to avoid this with many SQL languages is to use a top 1 or something like that to assure the engine that you will only return one result. Note that you have to do this even if you know the query will only return one result. Just because YOU know it doesn't mean that the engine knows it. The engine also has to protect you from future possibilities not just things as they are right this moment.
Update:
I noticed you updated your question to Oracle. So in that case you could limit the subquery to a single result using the where rownum = 1 clause. As other answer pointed out you'd have to use further logic to ensure that top 1 coming back is the right one. If you don't know which one is the right one then solve that first.
The thought also occurs to me that you might be misunderstanding what DISTINCT does. This ensures that the return results are unique - but there could still be multiple unique results.