In a single SQL statement/transaction I need to:
check the existence of a certain row based on a condition
update-or-insert the row
select the value of the row
The execution of these steps must be atomic (so once I started with phase 1, no other transactions must execute step 2 or 3)
I kinda find a way using MERGE INTO and LOCK TABLE statement and, but my concern it's the step between 2 and 3.
phase 1-2:
lock table DOC_COUNT in exclusive mode;
MERGE INTO DOC_COUNT AS mt USING (
SELECT * FROM TABLE (
VALUES
(?SEND_VALUE?, ?RECEIVE_VALUE?,1)
)
) AS vt (SEND, RECEIVE, QTY) ON (mt.SEND = vt.SEND AND mt.RECEIVE = vt.RECEIVE)
WHEN MATCHED THEN
UPDATE SET QTY = mt.QTY + 1
WHEN NOT MATCHED THEN
INSERT (SEND, RECEIVE, QTY) VALUES (vt.SEND, vt.RECEIVE, (SELECT COUNT(DOCUMENT_ID) AS DOC_CC_COUNT FROM V_DOC_COUNT WHERE DOCUMENT_ID <= ?DOC_ID_VALUE? AND RECEIVE = ?RECEIVE_VALUE?));
phase 3:
SELECT QTY FROM DOC_COUNT where SEND= ?SEND_VALUE? AND RECEIVE = ?RECEIVE_VALUE?;
How can I retrieve the value QTY after it was updated/insert without using SELECT FROM MERGE statement (unfortunately, my DB2 version is not supporting that feature) and without concurrency issues?
Related
How can I know the number of queries hitting a table in a particular time frame and what are those queries
Is it possible to get those stats for live tables hitting a redshift table?
This will give you the number of queries hitting a redshift table in a certain time frame:
SELECT
count(*)
FROM stl_wlm_query w
LEFT JOIN stl_query q
ON q.query = w.query
AND q.userid = w.userid
join pg_user u on u.usesysid = w.userid
-- Adjust your time frame accordignly
WHERE w.queue_start_time >= '2022-04-04 10:00:00.000000'
AND w.queue_start_time <= '2022-04-05 22:00:00.000000'
AND w.userid > 1
-- Set the table name here:
AND querytxt like '%my_main_table%';
If you need the actual queries text hitting the table in a certain timeframe, plus the queue and execution time and the user (remove if not needed):
SELECT
u.usename,
q.querytxt,
w.queue_start_time,
w.total_queue_time / 1000000 AS queue_seconds,
w.total_exec_time / 1000000 exec_seconds
FROM stl_wlm_query w
LEFT JOIN stl_query q
ON q.query = w.query
AND q.userid = w.userid
join pg_user u on u.usesysid = w.userid
-- Adjust your time frame accordignly
WHERE w.queue_start_time >= '2022-04-04 10:00:00.000000'
AND w.queue_start_time <= '2022-04-05 22:00:00.000000'
AND w.userid > 1
-- Set the table name here:
AND querytxt like '%my_main_table%'
ORDER BY w.queue_start_time;
If by "hitting a table you mean scan then they system table stl_scan lists all the accesses to a table and lists the query number that causes this scan. By writing a query to aggregate the information in stl_scan you can look at it by time interval and/or originating query. If this isn't what you mean you will need to clarify.
I don't understand what is meant by 'stats for live tables hitting a redshift table?'. What is meant by a table hitting a table?
I have two tables
Primary Diag
L021
L022
L023
L024
L025
L026
and Look_Up_New
ICD ICD2 Inclusion Type
L021 L021 3
L022 L022 2
L023 L023 2
L024 L024 4
L025 L025 5
L026 L026 4
L027 L029 5
there are two relationship one active and the other not
The active one is ICD
when I wrote the below dax for the active one it works fine
Diag 1 = IF(diag[Primary Diag]=BLANK(),"X",
IF(RELATED(Look_Up_New[ICD]) = BLANK(),"X",
RELATED(Look_Up_New[Inclusion Type])))
but when i wrote for the inactive one i got an error
Diag 2 = CALCULATE(IF(diag[Sec. Diag 2]=BLANK(),"X",
IF(RELATED(Look_Up_New[ICD2]) = BLANK(),"X",
RELATED(Look_Up_New[Inclusion Type]))),
USERELATIONSHIP(Look_Up_New[ICD2],Diag[Primary Diag]))
How can I correct it
The reason this fails is that CALCULATE forces a context transition (i.e. it transforms row context into filter context), which means RELATED no longer has the row context it needs to operate.
Note this remark from the documentation:
The RELATED function needs a row context; therefore, it can only be used in calculated column expression, where the current row context is unambiguous, or as a nested function in an expression that uses a table scanning function. A table scanning function, such as SUMX, gets the value of the current row value and then scans another table for instances of that value.
I'd suggest a slightly different approach:
Diag 1 =
CALCULATE ( SELECTEDVALUE ( Look_Up_New[Inclusion Type], "X" ) )
Diag 2 =
CALCULATE (
SELECTEDVALUE ( Look_Up_New[Inclusion Type], "X" ),
USERELATIONSHIP ( Diag[Primary Diag], Look_Up_New[ICD2] )
)
I'm trying to UPDATE a temporary transaction table with values from a holdings table. The fields I want to get are from the holding with the lowest date that is higher than the transaction date.
When I use below SELECT statement, the right values are shown:
SELECT h.*
FROM transaction_tmp tt
JOIN holdings h
ON tt.isin = h.isin
AND tt.portfolio = h.portfolio
WHERE h.start_date > tt.tr_date
ORDER BY h.start_date
LIMIT 1
However, when I use below UPDATE statement, incorrect values are selected/updated in transaction_tmp:
UPDATE transaction_tmp tt
JOIN holdings h
ON tt.isin = h.isin
AND tt.portfolio = h.portfolio
SET
tt.next_id = h.id,
tt.next_start_date = h.start_date
WHERE h.start_date > tt.tr_date
ORDER BY h.start_date
LIMIT 1
I'm thinking the WHERE statement is not working appropriately, but unfortunately I cannot figure out how to fix it.
Appreciate any help here!
-Joost
should work using a subquery
UPDATE transaction_tmp tt
JOIN (
SELECT h.*
FROM transaction_tmp tt
JOIN holdings h
ON tt.isin = h.isin
AND tt.portfolio = h.portfolio
WHERE h.start_date > tt.tr_date
ORDER BY h.start_date
LIMIT 1
) tx on ON tt.isin = tx.isin
AND tt.portfolio = tx.portfolio
SET
tt.next_id = tx.id,
tt.next_start_date = tx.start_date
I'm surprised your syntax works. The MySQL documentation is pretty clear that LIMIT and ORDER BY are only allowed when there is a single table reference:
UPDATE [LOW_PRIORITY] [IGNORE] table_reference
SET assignment_list
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
They are not allowed for the multiple table version of UPDATE:
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET assignment_list
[WHERE where_condition]
. . .
For the multiple-table syntax, UPDATE updates rows in each table named in table_references that satisfy the conditions. Each matching row is updated once, even if it matches the conditions multiple times. For multiple-table syntax, ORDER BY and LIMIT cannot be used.
I get an error if I try such syntax.
I have 2 tables with information in them. I need to update the SelfServiceUserName column in table A_CLIENT with the value from the SubstVarValue column of the A_DEV_SUBSTVAR_VALUE table when the ClientUID and DeviceID match and the SubstVarName from the A_DEV_SUBSTVAR_VALUE table = samaccount name. Here is the query I've tried to run but I keep getting errors:
UPDATE A_CLIENT
SET SelfServiceUserName = (SELECT SubstVarValue
FROM A_DEV_SUBSTVAR_VALUE
WHERE A_DEV_SUBSTVAR_VALUE.SubstVarName = 'samaccountname')
WHERE A_CLIENT.ClientUID = A_DEV_SUBSTVAR_VALUE.DeviceID
I always write a join between the two tables first to get the rows I want side by side and make sure I have the JOIN clause correct.
SELECT p.ProductID, p.ProductName, p.Price AS OldPrice, n.Price as NewPrice
FROM Products as p
JOIN NewPrices as n on p.ProductID = n.ProductID
Once I have done that it's easy to change it into an update statement by replacing the SELECT clause with an UPDATE and SET:
UPDATE p
SET Price = n.Price
FROM Products as p
JOIN NewPrices as n on p.ProductID = n.ProductID
Note you don't alias the Price on the left side of the SET clause, because it is necessarily from the p (Product) table, so there is no ambiguity. You must still alias the Price on the right of the equals because it could be the field coming from either the p (Product) or n (NewPrice) table.
You could also use a CTE (Common Table Expression) if your SQL engine supports it:
WITH x AS (
SELECT p.ProductID, p.ProductName, p.Price AS OldPrice, n.Price as NewPrice
FROM Products as p
JOIN NewPrices as n on p.ProductID = n.ProductID
)
UPDATE x set OldPrice = NewPrice
Try something like
update a_client c
inner join a_dev_substvar_value d on
c.clientuid = d.deviceid
set
c.selfserviceusername = d.substvarvalue
where
d.substvarname = 'samaccountname';
Note, you should try avoid writing select statements in your were clause because it is run for ever row returned. This can be a big performance hit.
That should work.
I am using Java DB (Java DB is Oracle's supported version of Apache Derby and contains the same binaries as Apache Derby. source: http://www.oracle.com/technetwork/java/javadb/overview/faqs-jsp-156714.html#1q2).
I am trying to update a column in one table, however I need to join that table with 2 other tables within the same database to get accurate results (not my design, nor my choice).
Below are my three tables, ADSID is a key linking Vehicles and Customers and ADDRESS and ZIP in Salesresp are used to link it to Customers. (Other fields left out for the sake of brevity.)
Salesresp(address, zip, prevsale)
Customers(adsid, address, zipcode)
Vehicles(adsid, selldate)
The goal is to find customers in the SalesResp table that have previously purchased a vehicle before the given date. They are identified by address and adsid in Customers and Vechiles respectively.
I have seen updates to a column with a single join and in fact asked a question about one of my own update/joins here (UPDATE with INNER JOIN). But now I need to take it that one step further and use both tables to get all the information.
I can get a multi-JOIN SELECT statement to work:
SELECT * FROM salesresp
INNER JOIN customers ON (SALESRESP.ZIP = customers.ZIPCODE) AND
(SALESRESP.ADDRESS = customers.ADDRESS)
INNER JOIN vehicles ON (Vehicles.ADSId =Customers.ADSId )
WHERE (VEHICLES.SELLDATE<'2013-09-24');
However I cannot get a multi-JOIN UPDATE statement to work.
I have attempted to try the update like this:
UPDATE salesresp SET PREVSALE = (SELECT SALESRESP.address FROM SALESRESP
WHERE SALESRESP.address IN (SELECT customers.address FROM customers
WHERE customers.adsid IN (SELECT vehicles.adsid FROM vehicles
WHERE vehicles.SELLDATE < '2013-09-24')));
And I am given this error: "Error code 30000, SQL state 21000: Scalar subquery is only allowed to return a single row".
But if I change that first "=" to a "IN" it gives me a syntax error for having encountered "IN" (Error code 30000, SQL state 42X01).
I also attempted to do more blatant inner joins, but upon attempting to execute this code I got the the same error as above: "Error code 30000, SQL state 42X01" with it complaining about my use of the "FROM" keyword.
update salesresp set prevsale = vehicles.selldate
from salesresp sr
inner join vehicles v
on sr.prevsale = v.selldate
inner join customers c
on v.adsid = c.adsid
where v.selldate < '2013-09-24';
And in a different configuration:
update salesresp
inner join customer on salesresp.address = customer.address
inner join vehicles on customer.adsid = vehicles.ADSID
set salesresp.SELLDATE = vehicles.selldate where vehicles.selldate < '2013-09-24';
Where it finds the "INNER" distasteful: Error code 30000, SQL state 42X01: Syntax error: Encountered "inner" at line 3, column 1.
What do I need to do to get this multi-join update query to work? Or is it simply not possible with this database?
Any advice is appreciated.
If I were you I would:
1) Turn off autocommit (if you haven't already)
2) Craft a select/join which returns a set of columns that identifies the record you want to update E.g. select c1, c2, ... from A join B join C... WHERE ...
3) Issue the update. E.g. update salesrep SET CX = cx where C1 = c1 AND C2 = c2 AND...
(Having an index on C1, C2, ... will boost performance)
4) Commit.
That way you don't have worry about mixing the update and the join, and doing it within a txn ensures that nothing can change the result of the join before your update goes through.