SELECT and SET with ROWCOUNT - sql-server-2008-r2

I have a SP with which I fetch a defined amount of rows. How can I change the value of a column in the fetched rows? Such as 'has been fetched' = 1.
Any advice?
EDIT:
The SP looks something like this
SET ROWCOUNT #numberOfRows
SELECT * FROM tableA where notSent = 1
I would like to change the 'notSent' colum for all the rows that i fetch. Is this possible?

1) Don't use Select * in a stored procedure - always specifically list the fields required as shown below - replace field1,2,3 etc with the actual fields you want returned.
OK - Modified answer:
2) Set a flag on the columns you want to select and update with a value that will not be otherwise programmatically set - e.g. -1 - Then select these records, then update them to set the final value required. Doing it this way will avoid the possibility that you will update a different set of records to those selected, due to inserts occurring half-way through the stored procedure's execution. You could also avoid this by use of locks, but the way below is going to be far healthier.
UPDATE Table set notSent = -1 WHERE notSent = 0
SELECT ... from Table where notSent = -1
UPDATE Table set notSent = 1 where notSent = -1

Related

How do I merge a frequency count back onto a table in postgresql?

I am attempting to count the number of each category and merge it back onto the table by overwriting the table in postgresql.
This is the main table I have (Named Titanic, containing the columns in question):
PassengerId
Group
0001_01
1
0002_01
2
0003_01
3
0003_02
3
I've altered the table by adding a new numeric column "GroupSize" which I want to contain the frequency counts of each group category. So record 1, would be a count of 1, record 2 would be a count of 1 and record 3 and 4 would both be a count of 2. And I want my main "Titanic" table to be retained as opposed to creating a new table or view so ideally using an "Update" statement to impute values into "GroupSize";
I have created a view to contain group the corresponding frequency counts from this code:
CREATE OR REPLACE VIEW "GroupSize"("Group", "GroupSize") AS
select "Group", count("Group") from "Titanic" GROUP BY "Group";
which outputs this:
Group
GroupSize
1
1
2
1
3
2
And I've tried an Update statement to use this view to add data into my "GroupSize" column from "Titanic" like such:
UPDATE "Titanic"
SET "GroupSize" = (SELECT "GroupSize" from "GroupSize")
WHERE "Group" IN (SELECT "Group" from "GroupSize");
I have been unsuccessful in getting this UPDATE statement to work mainly because I get an error: "more than one row returned by a subquery used as an expression". I am pretty new to SQL so ny help would be appreciated.
You almost had it right. The value used in SET is dynamic based off the row being modified. All you have to do is add a WHERE clause to it to ensure it picks the right value from the view.
UPDATE "Titanic"
SET "GroupSize" = (
SELECT "GroupSize" from "GroupSize"
where "Titanic"."Group" = "GroupSize"."Group"
-- (Pedantic safety limit, just in case)
limit 1
)
Beware, though, this will modify every row, setting NULL for values not found in the view. To have it preserve "GroupSize" column for rows without a match in the view, tack on another WHERE clause:
UPDATE "Titanic"
SET "GroupSize" = (
SELECT "GroupSize" from "GroupSize"
where "Titanic"."Group" = "GroupSize"."Group"
limit 1
)
WHERE "Group" IN (SELECT "Group" from "GroupSize");
Do not actually Update you main table, just create the view to hold the group size. This eliminates maintenance headaches when performing DML on the table, image what extra you need to transfer one group to another. With the count only in the view, you do nothing extra. You get the count of id in each group with the window version of count. (see demo)
create or replace view titanic_vw as
select passengerid "Passenger Id"
, passenger_group "Group"
, count(*) over (partition by passenger_group) "Group Size"
from titanic;

How to write a query that substrats a value -1?

I wanted to do a simple query that decreases certain value in 1 unit.
I tried this but it seems to be wrong:
ALTER TABLE users ALTER COLUMN postcounter - 1
How can I do this simple query?
try this :
UPDATE TABLE SET your_column_name = your_column_name - 1;

How to increment value in counter table

In my table I have the following scheme:
id - integer | date - text | name - text | count - integer
I want just to count some actions.
I want put 1 when date = '30-04-2019' not exist yet.
I want put +1 when is row already exist.
My idea is:
UPDATE "call" SET count = (1 + (SELECT count
FROM "call"
WHERE date = '30-04-2019'))
WHERE date = '30-04-2019'
But it is not working when row doesn't exist.
It is possible without some extra triggers, etc...
You can use a writeable CTE to achieve this. Additionally the UPDATE statement can be simplified to a simple set count = count + 1 there is no need for a sub-select.
with updated as (
update "call"
set count = count + 1
where date = '30-04-2019'
returning id
)
insert into "call" (date, count)
select '30-04-2019', 1
where not exists (select *
form updated);
If the update did not find a row, the where not exists condition will be true and the insert will be executed.
Note that the above is not safe for concurrent execution from multiple transactions. If you want to make this safe, create a unique index on the date column. Then use an INSERT ... ON CONFLICT instead:
insert into "call" (date, count)
values ('30-04-2019', 1)
on conflict (date)
do update
set count = "call".count + 1;
Again: the above requires a unique index (or constraint) on the date column.
Unrelated to the immediate problem, but: storing dates in a text column is a really, really bad idea. You should change your table definition and change the data type for the "date" column to date.

Select SQL to pick next non matching record for same date

I have table name as client_audit, unique and identity column is recno, clientcode, auditdate, Auditflag and has other multiple columns which are tend to be change and recorded as before audit and after audit image for same client code.
auditflag 1 means before change and auditflag 2 is after change image.
If I run select * from client_audit where audit_flag = 1 then record count is coming as 30000100
If I run select * from client_audit where audit_flag = 2 then record count is coming as 30000000
So actually for 100 records I don't have after audit image.
Now records are getting created in pair like for same clientcode before and audit image will be created, their recnumber will be in sequence.
Is there any way from same table I can fetch those 100 record which only have before audit image and not after audit image considering recno as unique and identity and audit records will be in pair for same client code and for same audidate?
If I understood your table structure correctly try this
select * from client_audit where audit_flag = 1 and clientcode not in (select clientcode from client_audit where audit_flag = 2)
First, a free tip: If you are inserting both records to the database at the same time, you should use a transaction so that if one of the inserts fails, both of them will and you will not end up with orphan records like you do now.
To answer your question:
You can use not exists to get all the records where audit_flag = 1 that don't have a corresponding record with audit_flag = 2, based on clientcode and auditdate, like this:
select *
from client_audit as c1
where audit_flag = 1
and not exists
(
select 1
from client_audit as c2
where audit_flag = 2
and c1.clientcode = c2.clientcode
and c1.auditdate = c2.auditdate
)

updatexml for particular rows only

Context: I want to increase the allowance value of some employees from £1875 to £7500, and update their balance to be £7500 minus whatever they have currently used.
My Update statement works for one employee at a time, but I need to update around 200 records, out of a table containing about 6000.
I am struggling to workout how to modify the below to update more than one record, but only the 200 records I need to update.
UPDATE employeeaccounts
SET xml = To_clob(Updatexml(Xmltype(xml),
'/EmployeeAccount/CurrentAllowance/text()',187500,
'/EmployeeAccount/AllowanceBalance/text()',
750000 - (SELECT Extractvalue(Xmltype(xml),
'/EmployeeAccount/AllowanceBalance',
'xmlns:ts=\"http://schemas.com/\", xmlns:xt=\"http://schemas.com\"'
)
FROM employeeaccounts
WHERE id = '123456')))
WHERE id = '123456'
Example of xml column (stored as clob) that I want to update. Table has column ID that hold PK of employees ID EG 123456
<EmployeeAccount>
<LastUpdated>2016-06-03T09:26:38+01:00</LastUpdated>
<MajorVersion>1</MajorVersion>
<MinorVersion>2</MinorVersion>
<EmployeeID>123456</EmployeeID>
<CurrencyID>GBP</CurrencyID>
<CurrentAllowance>187500</CurrentAllowance>
<AllowanceBalance>100000</AllowanceBalance>
<EarnedDiscount>0.0</EarnedDiscount>
<NormalDiscount>0.0</NormalDiscount>
<AccountCreditLimit>0</AccountCreditLimit>
<AccountBalance>0</AccountBalance>
</EmployeeAccount>
You don't need a subquery to get the old balance, you can use the value from the current row; which means you don't need to correlate that subquery and can just use an in() in the main statement:
UPDATE employeeaccounts
SET xml = To_clob(Updatexml(Xmltype(xml),
'/EmployeeAccount/CurrentAllowance/text()',187500,
'/EmployeeAccount/AllowanceBalance/text()',
750000 - Extractvalue(Xmltype(xml),
'/EmployeeAccount/AllowanceBalance',
'xmlns:ts=\"http://schemas.com/\", xmlns:xt=\"http://schemas.com\"')
))
WHERE id in (123456, 654321, ...);