SQL Update statement updates one row multiple times, but is inconsistent - sql-server

The first question ever on here.
I have an update statement, which seems to have been working perfectly fine, previously.
Out of nowhere, the update statement seems to update a single row multiple times, but not for all rows, if that makes sense?
The statement is run via SQL agent and scheduled every 10 seconds (along with other steps)
Sorry if it's big or messy, I'm self-trained!
The first step, is to insert data into a table that needs to be updated on the main table, using a view.
For the audit trail, I then insert IDs into another table, to track what's being updated.
The problematic part of this statement is the update main table (DT_V_POTATTENDANCE).
Below that is an insert into the main table where an ID cannot be found in the view.
The rest of the script again is all part of the audit trail which is how I've found it updating a single row multiple times for whatever reason (but not every time if that makes sense?) and setting the records as updated so they don't keep updating.
Thanks for your help, really appreciate it.
SELECT DISTINCT * INTO _TEMPTABLEAPPROVEDATTENDANCE
from BE_RPT_PA_ATTENDANCE_TO_UPDATE
SET IDENTITY_INSERT _TEMPTABLEAPPROVEDATTENDANCEUPDATEDSIGNIDS ON
INSERT INTO _TEMPTABLEAPPROVEDATTENDANCEUPDATEDSIGNIDS (SIGNID)
SELECT SIGNID FROM DT_PA_POTATTENDANCE WHERE APPROVED = 1 AND UPDATED IS NULL
SET IDENTITY_INSERT _TEMPTABLEAPPROVEDATTENDANCEUPDATEDSIGNIDS OFF
declare #time datetime
set #time = (select getdate())
UPDATE DT_V_POTATTENDANCE
SET
DT_V_POTATTENDANCE.CB_H_MON = DT_V_POTATTENDANCE.CB_H_MON + Y.CB_H_MON,
DT_V_POTATTENDANCE.CB_M_MON = DT_V_POTATTENDANCE.CB_M_MON + Y.CB_M_MON,
DT_V_POTATTENDANCE.CB_H_TUE = DT_V_POTATTENDANCE.CB_H_TUE + Y.CB_H_TUE,
DT_V_POTATTENDANCE.CB_M_TUE = DT_V_POTATTENDANCE.CB_M_TUE + Y.CB_M_TUE,
DT_V_POTATTENDANCE.CB_H_WED = DT_V_POTATTENDANCE.CB_H_WED + Y.CB_H_WED,
DT_V_POTATTENDANCE.CB_M_WED = DT_V_POTATTENDANCE.CB_M_WED + Y.CB_M_WED,
DT_V_POTATTENDANCE.CB_H_THU = DT_V_POTATTENDANCE.CB_H_THU + Y.CB_H_THU,
DT_V_POTATTENDANCE.CB_M_THU = DT_V_POTATTENDANCE.CB_M_THU + Y.CB_M_THU,
DT_V_POTATTENDANCE.CB_H_FRI = DT_V_POTATTENDANCE.CB_H_FRI + Y.CB_H_FRI,
DT_V_POTATTENDANCE.CB_M_FRI = DT_V_POTATTENDANCE.CB_M_FRI + Y.CB_M_FRI,
DT_V_POTATTENDANCE.H_H_MON = DT_V_POTATTENDANCE.H_H_MON + Y.H_H_MON,
DT_V_POTATTENDANCE.H_M_MON = DT_V_POTATTENDANCE.H_M_MON + Y.H_M_MON,
DT_V_POTATTENDANCE.H_H_TUE = DT_V_POTATTENDANCE.H_H_TUE + Y.H_H_TUE,
DT_V_POTATTENDANCE.H_M_TUE = DT_V_POTATTENDANCE.H_M_TUE + Y.H_M_TUE,
DT_V_POTATTENDANCE.H_H_WED = DT_V_POTATTENDANCE.H_H_WED + Y.H_H_WED,
DT_V_POTATTENDANCE.H_M_WED = DT_V_POTATTENDANCE.H_M_WED + Y.H_M_WED,
DT_V_POTATTENDANCE.H_H_THU = DT_V_POTATTENDANCE.H_H_THU + Y.H_H_THU,
DT_V_POTATTENDANCE.H_M_THU = DT_V_POTATTENDANCE.H_M_THU + Y.H_M_THU,
DT_V_POTATTENDANCE.H_H_FRI = DT_V_POTATTENDANCE.H_H_FRI + Y.H_H_FRI,
DT_V_POTATTENDANCE.H_M_FRI = DT_V_POTATTENDANCE.H_M_FRI + Y.H_M_FRI,
DT_V_POTATTENDANCE.AA_H_MON = DT_V_POTATTENDANCE.AA_H_MON + Y.AA_H_MON,
DT_V_POTATTENDANCE.AA_M_MON = DT_V_POTATTENDANCE.AA_M_MON + Y.AA_M_MON,
DT_V_POTATTENDANCE.AA_H_TUE = DT_V_POTATTENDANCE.AA_H_TUE + Y.AA_H_TUE,
DT_V_POTATTENDANCE.AA_M_TUE = DT_V_POTATTENDANCE.AA_M_TUE + Y.AA_M_TUE,
DT_V_POTATTENDANCE.AA_H_WED = DT_V_POTATTENDANCE.AA_H_WED + Y.AA_H_WED,
DT_V_POTATTENDANCE.AA_M_WED = DT_V_POTATTENDANCE.AA_M_WED + Y.AA_M_WED,
DT_V_POTATTENDANCE.AA_H_THU = DT_V_POTATTENDANCE.AA_H_THU + Y.AA_H_THU,
DT_V_POTATTENDANCE.AA_M_THU = DT_V_POTATTENDANCE.AA_M_THU + Y.AA_M_THU,
DT_V_POTATTENDANCE.AA_H_FRI = DT_V_POTATTENDANCE.AA_H_FRI + Y.AA_H_FRI,
DT_V_POTATTENDANCE.AA_M_FRI = DT_V_POTATTENDANCE.AA_M_FRI + Y.AA_M_FRI
FROM _TEMPTABLEAPPROVEDATTENDANCE Y
WHERE DT_V_POTATTENDANCE.ATTENDANCEWEEKID = Y.ATTENDANCEWEEKID
AND Y.ATTENDANCEWEEKID IS NOT NULL
AND Y.TRAINEEID <> '0683-0001-107827'
INSERT INTO DT_V_POTATTENDANCE
([TRAINEEID]
,[POT]
,[WEEKSTARTDATE]
,[CB_H_MON]
,[CB_M_MON]
,[CB_H_TUE]
,[CB_M_TUE]
,[CB_H_WED]
,[CB_M_WED]
,[CB_H_THU]
,[CB_M_THU]
,[CB_H_FRI]
,[CB_M_FRI]
,[H_H_MON]
,[H_M_MON]
,[H_H_TUE]
,[H_M_TUE]
,[H_H_WED]
,[H_M_WED]
,[H_H_THU]
,[H_M_THU]
,[H_H_FRI]
,[H_M_FRI]
,[AA_H_MON]
,[AA_M_MON]
,[AA_H_TUE]
,[AA_M_TUE]
,[AA_H_WED]
,[AA_M_WED]
,[AA_H_THU]
,[AA_M_THU]
,[AA_H_FRI]
,[AA_M_FRI])
SELECT [TRAINEEID]
,[POT]
,[WEEKSTARTDATE]
,[CB_H_MON]
,[CB_M_MON]
,[CB_H_TUE]
,[CB_M_TUE]
,[CB_H_WED]
,[CB_M_WED]
,[CB_H_THU]
,[CB_M_THU]
,[CB_H_FRI]
,[CB_M_FRI]
,[H_H_MON]
,[H_M_MON]
,[H_H_TUE]
,[H_M_TUE]
,[H_H_WED]
,[H_M_WED]
,[H_H_THU]
,[H_M_THU]
,[H_H_FRI]
,[H_M_FRI]
,[AA_H_MON]
,[AA_M_MON]
,[AA_H_TUE]
,[AA_M_TUE]
,[AA_H_WED]
,[AA_M_WED]
,[AA_H_THU]
,[AA_M_THU]
,[AA_H_FRI]
,[AA_M_FRI]
FROM _TEMPTABLEAPPROVEDATTENDANCE
WHERE ATTENDANCEWEEKID IS NULL
AND TRAINEEID <> '0683-0001-107827'
UPDATE DT_PA_POTATTENDANCE
SET UPDATED = 1
FROM DT_PA_POTATTENDANCE
WHERE APPROVEDTIMESTAMP < #time and
TRAINEEID <> '0683-0001-107827' AND
APPROVED = 1 AND UPDATED IS NULL AND SIGNID IN (SELECT SIGNID FROM _TEMPTABLEAPPROVEDATTENDANCEUPDATEDSIGNIDS)
INSERT INTO _TEMPTABLEAPPROVEDATTENDANCEUPDATED
([ATTENDANCEWEEKID],[TRAINEEID]
,[POT]
,[WEEKSTARTDATE]
,[CB_H_MON]
,[CB_M_MON]
,[CB_H_TUE]
,[CB_M_TUE]
,[CB_H_WED]
,[CB_M_WED]
,[CB_H_THU]
,[CB_M_THU]
,[CB_H_FRI]
,[CB_M_FRI]
,[H_H_MON]
,[H_M_MON]
,[H_H_TUE]
,[H_M_TUE]
,[H_H_WED]
,[H_M_WED]
,[H_H_THU]
,[H_M_THU]
,[H_H_FRI]
,[H_M_FRI]
,[AA_H_MON]
,[AA_M_MON]
,[AA_H_TUE]
,[AA_M_TUE]
,[AA_H_WED]
,[AA_M_WED]
,[AA_H_THU]
,[AA_M_THU]
,[AA_H_FRI]
,[AA_M_FRI])
SELECT [ATTENDANCEWEEKID],[TRAINEEID]
,[POT]
,[WEEKSTARTDATE]
,[CB_H_MON]
,[CB_M_MON]
,[CB_H_TUE]
,[CB_M_TUE]
,[CB_H_WED]
,[CB_M_WED]
,[CB_H_THU]
,[CB_M_THU]
,[CB_H_FRI]
,[CB_M_FRI]
,[H_H_MON]
,[H_M_MON]
,[H_H_TUE]
,[H_M_TUE]
,[H_H_WED]
,[H_M_WED]
,[H_H_THU]
,[H_M_THU]
,[H_H_FRI]
,[H_M_FRI]
,[AA_H_MON]
,[AA_M_MON]
,[AA_H_TUE]
,[AA_M_TUE]
,[AA_H_WED]
,[AA_M_WED]
,[AA_H_THU]
,[AA_M_THU]
,[AA_H_FRI]
,[AA_M_FRI]
FROM _TEMPTABLEAPPROVEDATTENDANCE
WHERE TRAINEEID <> '0683-0001-107827'
drop table _TEMPTABLEAPPROVEDATTENDANCE

I found the reason why it was doing it!
Below part of my script was making it run and run again.
The user in question, we have an MIS that sets the field "Approved" to 1, the script above then updates the master table DT_V_POTATTENDANCE, but it wasn't setting the field "Updated" to 1 because the users time was 3 minutes out!
UPDATE DT_PA_POTATTENDANCE
SET UPDATED = 1
FROM DT_PA_POTATTENDANCE
WHERE APPROVEDTIMESTAMP < #time and
TRAINEEID <> '0683-0001-107827' AND
APPROVED = 1 AND UPDATED IS NULL AND SIGNID IN
(SELECT SIGNID FROM _TEMPTABLEAPPROVEDATTENDANCEUPDATEDSIGNIDS)
Thanks for all your help guys, appreciate it!

Related

Taking Previous Months' Date Automatically in PLSQL

Hello I have a procedure and questions about it. This procedure is used for extracting data then inserting them into one table. When I test my code, I have to enter some parameters for executing procedure.
`--this is how I execute the procedure
begin
GPU_DATA_EXTRACTOR(to_date('31/08/2021','DD/MM/YYYY'));
end;`
But what I want to do is that when the billdate parameter is NULL, the procedure should execute last day of the previous month as a parameter automatically. How can I make this change? I am open to any update advices thank you from now.
Updated the script below.
create or replace procedure GPU_DATA_EXTRACTOR_TEST(pid_billdate DATE DEFAULT LAST_DAY(ADD_MONTHS(TRUNC(SYSDATE), -1))) is
c_limit CONSTANT PLS_INTEGER DEFAULT 10000;
CURSOR c1 IS
SELECT DISTINCT intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab
WHERE abr.CHRG_TP = 'INSTALLMENT'
AND abr.TAX_CATG_ID = 'NOTAX'
AND abr.acct_bill_id = ab.acct_bill_id
AND ab.bill_date = pid_billdate;
TYPE prod_ids_t IS TABLE OF apld_bill_rt.intl_prod_id%TYPE INDEX BY PLS_INTEGER;
l_prod_ids prod_ids_t;
begin
execute immediate 'truncate table GPU_INV_TEST';
OPEN c1;
LOOP
FETCH c1 BULK COLLECT INTO l_prod_ids LIMIT c_limit;
EXIT WHEN l_prod_ids.COUNT = 0;
FORALL indx IN 1 .. l_prod_ids.COUNT
INSERT INTO GPU_INV_TEST
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba2.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
bill_acct ba2,
prod_cmpg pg
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+)
AND ABR.intl_prod_id = l_prod_ids(indx)
UNION
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba1.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
prod_cmpg pg
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
--AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba1.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+)
AND ABR.intl_prod_id = l_prod_ids(indx);
COMMIT;
END LOOP;
CLOSE c1;
end;
You can add a default value for your parameters. Take the following function as an example:
CREATE OR REPLACE FUNCTION sf_showDefault
(
p_in DATE DEFAULT LAST_DAY(ADD_MONTHS(TRUNC(SYSDATE), -1))
)
RETURN DATE
IS
BEGIN
RETURN p_in;
END sf_showDefault;
/
When no parameters are entered it gets a truncated SYSDATE and subtracts one month, then if finds the last day of that month. All the function does is return that data (or the one that you pass in...if you feel like it).
Here is a DBFiddle showing the effect of DEFAULT parameters (LINK)

SQL Server trigger for changing value of column of inserted row according to delta from other table after insert?

I have 2 tables in my SQL Server database, for example [Camera] and [CameraData]. How to write a trigger which will change value in [CameraData] after row is inserted into [CameraData] due to delta in [Camera].
For example we have 2 cameras in [Camera]:
Camera 1 with {id} = 1 and {delta} = null
Camera 2 with {id} = 2 and {delta} = 3
So when we have automated insert into table [CameraData], f.e. :
Id_camera = 2, angle = 30, Changed = null
In that case we need to check either we have delta in [Camera] on camera 2 and if that's true we need to modify insert to:
Id_camera = 2, angle = 33 (angle + Camera.Delta), Changed = True
Update 1
According to comment [3] is the column in table [CameraData] where angle is placed
CREATE TRIGGER Delta_Angle
ON CameraData
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE CameraData
SET DeltaFlag = 1, [3] = inserted.[3] + i.DeltaAngle
FROM CameraData h
INNER JOIN Camera i ON h.ID_Camera = i.ID_Camera
WHERE i.DeltaAngle != ''
END
This is very much a stab in the dark, as your sample SQL isn't at all representative of the data your describe in your question, however, maybe something like:
CREATE TRIGGER Delta_Angle ON CameraData
AFTER INSERT AS
BEGIN
SET NOCOUNT ON;
UPDATE C
SET Angle = C.Angle + i.delta
FROM Camera
JOIN inserted i ON C.CameraID = i.CameraID;
END
Notice that I refer to inserted; your trigger wasn't. Also, I'm not sure about your clause i.DeltaAngle != ''. Considering that DeltaAngle appears to be an int, it can never have a value of '' (however, '' would be implicitly converted to the value 0).
If this doesn't help, I (again) suggest you read Sean's link and update your post accordingly.

slow SQLite read speed (100 records a second)

I have a large SQLite database (~134 GB) that has multiple tables each with 14 columns, about 330 million records, and 4 indexes. The only operation used on the database is "Select *" as I need all the columns(No inserts or updates). When I query the database, the response time is slow when the result set is big (takes 160 seconds for getting ~18,000 records).
I have improved the use of indexes multiple times and this is the fastest response time I got.
I am running the database as a back-end database for a web application on a server with 32 GB of RAM.
is there a way to use RAM (or anything else) to speed up the query process?
Here is the code that performs the query.
async.each(proteins,function(item, callback) {
`PI[item] = []; // Stores interaction proteins for all query proteins
PS[item] = []; // Stores scores for all interaction proteins
PIS[item] = []; // Stores interaction sites for all interaction proteins
var sites = {}; // a temporarily holder for interaction sites
var query_string = 'SELECT * FROM ' + organism + PIPE_output_table +
' WHERE ' + score_type + ' > ' + cutoff['range'] + ' AND (protein_A = "' + item + '" OR protein_B = "' + item '") ORDER BY PIPE_score DESC';
db.each(query_string, function (err, row) {
if (row.protein_A == item) {
PI[item].push(row.protein_B);
// add 1 to interaction sites to represent sites starting from 1 not from 0
sites['S1AS'] = row.site1_A_start + 1;
sites['S1AE'] = row.site1_A_end + 1;
sites['S1BS'] = row.site1_B_start + 1;
sites['S1BE'] = row.site1_B_end + 1;
sites['S2AS'] = row.site2_A_start + 1;
sites['S2AE'] = row.site2_A_end + 1;
sites['S2BS'] = row.site2_B_start + 1;
sites['S2BE'] = row.site2_B_end + 1;
sites['S3AS'] = row.site3_A_start + 1;
sites['S3AE'] = row.site3_A_end + 1;
sites['S3BS'] = row.site3_B_start + 1;
sites['S3BE'] = row.site3_B_end + 1;
PIS[item].push(sites);
sites = {};
}
}
The query you posted uses no variables.
It will always return the same thing: all the rows with a null score whose protein column is equal to its protein_a or protein_b column. You're then having to filter all those extra rows in Javascript, fetching a lot more rows than you need to.
Here's why...
If I'm understanding this query correctly, you have WHERE Score > [Score]. I've never encountered this syntax before, so I looked it up.
[keyword] A keyword enclosed in square brackets is an identifier. This is not standard SQL. This quoting mechanism is used by MS Access and SQL Server and is included in SQLite for compatibility.
An identifier is something like a column or table name, not a variable.
This means that this...
SELECT * FROM [TABLE]
WHERE Score > [Score] AND
(protein_A = [Protein] OR protein_B = [Protein])
ORDER BY [Score] DESC;
Is the same as this...
SELECT * FROM `TABLE`
WHERE Score > Score AND
(protein_A = Protein OR protein_B = Protein)
ORDER BY Score DESC;
You never pass any variables to the query. It will always return the same thing.
This can be seen here when you run it.
db.each(query_string, function (err, row) {
Since you're checking that each protein is equal to itself (or something very like itself), you're likely fetching every row. And it's why you have to filter all the rows again. And that is one of the reasons why your query is so slow.
if (row.protein_A == item) {
BUT! WHERE Score > [Score] will never be true, a thing cannot be greater than itself except for null! Trinary logic is weird. So only if Score is null can that be true.
So you're returning all the rows whose score is null and the protein column is equal to protein_a or protein_b. This is a lot more rows than you need, I guess you have a lot of rows with null scores.
Your query should incorporate variables (I'm assuming you're using node-sqlite3) and pass in their values when you execute the query.
var query = " \
SELECT * FROM `TABLE` \
WHERE Score > $score AND \
(protein_A = $protein OR protein_B = $protein) \
ORDER BY Score DESC; \
";
var stmt = db.prepare(query);
stmt.each({$score: score, $protein: protein}, function (err, row) {
PI[item].push(row.protein_B);
...
});

TSQL Update variable only if there is a value

I have an update statement that looks like this:
UPDATE sessions
SET currentStep = #currentStep,
chosenDepartment = #chosenDepartment,
proposedTimes = #proposedTimes
WHERE sessionID = #sessionID
AND empID = #empID;
I use the same stored procedure for multiple updates as each step in my process gets an additional value along the way.
My question: is there a way to only do this :
chosenDepartment = #chosenDepartment
if #cosenDepartment actually contains a value?
If I do it every time, it will overwrite it with blank data if I don't pass anything to it.
Try this:
UPDATE sessions
SET currentStep = #currentStep,
chosenDepartment = CASE WHEN #chosenDepartment IS NOT NULL THEN #chosenDepartment ELSE chosenDepartment END,
proposedTimes = #proposedTimes
WHERE sessionID = #sessionID
AND empID = #empID;
or this
UPDATE sessions
SET currentStep = #currentStep,
chosenDepartment = COALESCE(#chosenDepartment, chosenDepartment),
proposedTimes = #proposedTimes
WHERE sessionID = #sessionID
AND empID = #empID;
Note #1: SQL Server will translate COALESCE(#chosenDepartment, chosenDepartment)
into CASE WHEN #chosenDepartment IS NOT NULL THEN #chosenDepartment ELSE chosenDepartment END.
Note #2: If you want to avoid NULL #chosenDepartment but also if you want to avoid the updates with empty strings or 0 then you could use NULLIF function thus: COALESCE(NULLIF(#chosenDepartment,''), chosenDepartment) or COALESCE(NULLIF(#chosenDepartment,0), chosenDepartment).
You may put if statement before tsql so if #chosenDepartment is blank then tsql won't run.

sql server: how do i get the last record that was inserted?

i am doing this:
With rs
.AddNew ' create a new record
' add values to each field in the record
.Fields("datapath") = dpath
.Fields("analysistime") = atime
.Fields("reporttime") = rtime
.Fields("lastcalib") = lcalib
.Fields("analystname") = aname
.Fields("reportname") = rname
.Fields("batchstate") = bstate
.Fields("instrument") = instrument
.Update ' stores the new record
End With
' get the last id
Set rs = cn.Execute("SELECT SCOPE_IDENTITY()", , adCmdText)
this is not working properly. it is returning NULL
It's not working because your updates and your second execute are in different scopes.
You may want SELECT IDENT_CURRENT('tablename')
IDENT_CURRENT is fine in a single user environment.
You're already on the record when you update.
.Update
lTheNewID = .Fields("ThisTableID")
lTheNewID will hold the value of the new record.

Resources