Update SQL Server table with one time use values from another table - sql

I have a table of users that has the usual suspects, name, email, etc. As the users complete an activity (queried from another table), I need to award them a gift card code.
update users
set giftcardcode = 'code from other table'
where email in (select email from useractivity where necessary conditions are met)
I have a table of unique gift card codes that are unique, one-time use codes. So I need to update my user table, setting the award code field equal to a distinct, unused gift card code from the gift card code table. Then I need to mark the 'used' field in the gift card table to 'Y'.
The goal is to do this with SQL and not any programming. I'm stumped.

I think there is a Many To Many relationship between User table and Activity table.
So, you can use a trigger to execute a query when update.
Each time a row will be updated in the Activity table, the trigger will do something.
It will UPDATE the User table by adding a new gift code.
I think you can add an attribute in your GiftCode table to easily check if the code as already been used. An you can get an unused code like that :
// Retrieve an unused code based on a BIT attribute.
SELECT TOP 1 [Code] FROM [GiftCode] WHERE IS_UNUSED = 1;
Don't forget to update this Gift code after using it.
You can use a SELECT statement including a sub SELECT statement to get a code too :
// Retrieve an unused code based on User table used codes.
SELECT TOP 1 [Code] FROM [GiftCode] WHERE [Code] NOT IN (SELECT [Code] FROM [User]);
It works well if you don't have too much users.
Otherwise , the first statement will be more efficient.
Don't forget to update the User table.
Now you can easily use one of these previous statement in a UPDATE statement.
It will be something like that :
UPDATE [User] SET [Code] = (
SELECT TOP 1 [Code] FROM [GiftCode] WHERE [Code] NOT IN (
SELECT [Code] FROM [User]))
WHERE USER_ID = // ...;
You can perform this in a trigger.
You can use a stored procedure, it's more efficient and will wrap all the SQL code in a compiled function. Then you can call it in your trigger.
You can execute a stored procedure in a job (see SQL Server Agent jobs) too.

create a Trigger on your table for update and do what you want inside it using inserted and deleted

Related

Webapp - should a constraint be checked at database or application, or both

Simplified context:
let say I have 2 table in my database: Room(id, maxContract) and Contract(id, roomid, status)
let say I have a room 17 which allow max 2 clients, now I would search the Contract table of row roomid = 17 and status = active, if the more more than max (in this case 2) rows, I would prevent further INSERT until a contract expire.
Question:
Now I see 2 ways of doing this, first is in the database itself, maybe on a TRIGGER, and the second is doing this in my webapp DAO: query the Contract table to get the count, if-else to check the logic and only run the insert if true
But I am just a newbie, I don't know what is the best (or common) approach, which way I should do it? If this was my personal app, I would do both for max security, but designing a web I had to also take performance into consideration.
In case of frontend - backend, I know that validation is mandatory at backend and optional at the frontend, but between backend-database I don't know exactly
(In case this is opinion-based and there is no best-practice, I would like to know the pros and cons of both implementation)
EDIT:
to be more exact: user click JOIN ROOM => call an insertToRoom() method
+solution 1:
insertToRoom(){
if (roomIsAvailable()){
execute INSERT query;
}
else alert: "room is full";
}
roomIsAvailable() is a method to query and count how many contracts are bound to the room
+solution 2:
insertToRoom(){
execute INSERT query;
}
database:
CREATE TRIGGER before INSERT
if (some code to count the rooms)
ROLLBACK TRANSACTION;
in this case, if an unavailable room is join, database will return error, which in turn cause the execute INSERT query in the application to return false.
Either way, the falsy data is not inserted end the end user will get an error alert
I expect that more than one user can work with your application.
If you will get the current status from DB to the application, evaluate the condition there and then you will run the insert into DB table, then the condition can be violated. Let's imagine this sequence of steps:
User A read the current status from DB.
User B read the current status from DB.
User A evaluate the condition with result "there is a space for one client".
User B evaluate the condition with result "there is a space for one client".
User A update DB -> the room is full.
User B update DB -> in the room is more than allowed number of clients.
So that is not an option.
You can use triggers (as you mentioned), if your DB has such possibility.
You can also create one SQL statement which will check conditions and update the record in DB in one step (atomically). It depends on your DB engine, whether it is possible.
Update 2022-05-27
I was asked to explain in detail the atomic insert solution.
I'm not MySQL guru and I'm pretty sure, that there is more elegant way, how to do it, but something like this works too:
Let's create required DB objects first:
create table Room(
id INT,
maxContract INT);
create table Contract(
id INT AUTO_INCREMENT,
roomid INT,
status VARCHAR(30),
PRIMARY KEY(id)
);
create view UsedSpace as
select r.id as roomid, count(c.id) as used
from Room r
left outer join Contract c on c.roomid = r.id and status='active'
group by r.id;
Then we can use this statement to insert new row to Contract table:
insert into Contract(roomid, status)
select r.id, 'active'
from Room r
inner join UsedSpace us on r.id = us.roomid and r.maxContract > us.used
where id = 17;
When there is too much active contracts, then new row is not inserted.
You can check if the row was inserted or not via
select row_count();
Here is a fiddle to show results quickly.

SQL Transaction Set Temporary Value

I am relatively new to databases and SQL, and I am not clear on how or whether transactions may relate to a problem that I am trying to solve. I want to be able to temporarily set a value in a database table, run some query, and then clear out the value that was set, and I don't want any operations outside of the transaction to be able to see or alter the temporary value that was set.
The reason I am doing this is so that I can create predefined views that query certain data depending on variables such as the current user's id. In order for the predefined view to have access to the current user's id, I would save the id into a special table just before querying the view, then delete the id immediately afterward. I don't want to worry about some other user overwriting the current user's id while the transaction is in process. Is this a proper use for a transaction?
I am using H2 if that makes a difference.
SET #tempVar=value;
I don't know if you really need to go through the pain of creating a temp table and setting the value. This seems far simpler.
You can then do - SELECT * FROM TABLE_NAME WHERE COLUMN=#tempVar;
I think you want a Procedure or Function. Both can take a parameter as input.
ex.
CREATE PROCEDURE pr_emp
(
#input INT
)
AS
SELECT *
FROM myTable
WHERE emp_id = #input
ex.
CREATE FUNCTION v_empid (#input INT)
RETURNS TABLE
AS
RETURN
SELECT * FROM myTABLE WHERE emp_id = #input;
These could let you to access information for an empid. For example:
SELECT * FROM v_empid(32)

How to insert into the table a user name record

I've a table. In this table I have two columns - 'insert_name' and 'modified_name'. I need to insert into this columns data about who has inserted data into the table('insert_name') and who has changed these data in the table (modified_name). How it can be done?
You are looking for basic DML statements.
If your record is already in the table, then you need to UPDATE it. Otherwise, when you are about to add your record to it and it doesn't already exist in the destination table then you are looking for INSERT INTO statement.
Example of updating information for record with first id:
UPDATE yourtable SET insert_name = 'value1', modified_name = 'value2' WHERE id = 1
Example of inserting new record:
INSERT INTO yourtable(id, company_name, product_name, insert_name)
VALUES (1, 'Google', 'PC', 'value1')
If you are looking for automatic changes to those columns then you need to look into triggers.
Remember that more often than not you may find that the application connecting to the database is using single database user in which case you probably know the context within the application itself (who inserts, who updates). This does eliminate triggers and put the task straight on simple insert/update commands from within your application layer.
You might be able to use the CURRENT_USER function to find the name of the user making the change.
The value from this function could then be used to update the appropriate column. This update could be done as part of the INSERT or UPDATE statement. Alternatively use an INSERT or UPDATE trigger.
Personally I avoid triggers if I can.
For those 2 columns add Current_User as Default constraint.
As the first time Insert Statement will save them with current login user names. For update write an Update trigger with the same Current_User statement for the column Modified_Name.
If and only if your application business logic can't update the column modified_nme then only go for Trigger.
See the use of Current_Use
https://msdn.microsoft.com/en-us/library/ms176050.aspx

Unable to do update table from Apex 5 button Error mentions Cannot Insert NULL

Hi People of the Palace
I am not having luck here and tried a lot of things and seems as if I am not able to get the value from the field which needs to update.
There are 2 fields within Apex 5 which I want to update if something if the value is changed from default. :QUANTITY which is a text field inside of a Tabular form and :DISC which is also a text field in the same row.
There can be single or multiple rows to that needs to be updated and this is usually where you set the option "updated rows and columns only"
The table SALES_TEMP does has columns ID, NAME, QUANTITY_TO_SELL, DISCOUNT.
The PL/SQL code that is assigned in the process to do this update is as follows.
BEGIN
update SALES_TEMP
set QUANTITY_TO_SELL=:QUANTITY, DISCOUNT=:DISC;
end;
When I try and update the fields, it will return with
Cannot insert NULL into QUANTITY_TO_SELL
and similar with the DISCOUNT field.
Now I know there is nothing wrong with the query because if I do this:
BEGIN
update SALES_TEMP
set QUANTITY_TO_SELL='2', DISCOUNT='5';
end;
It does in fact update the table, but it will then do this update to all rows in the table because I have no where clause.
I have had a look through the different options and cannot seem to find why it does not select the data from the fields. My main issue is, I have an exact same query running doing an insert which works.
Also from Apex's Sql Command line option if I run.
update SALES_TEMP
set QUANTITY_TO_SELL=:QUANTITY, DISCOUNT=:DISC;
I get a popup requesting values for :QUANTITY and :DISC and it then updates the columns so something tells me that this is not getting the values from these text fields.
The SQL command to add to populate the fields are
select ID, NAME, QUANTITY_TO_SELL as QUANTITY, DISCOUNT as DISC from SALES_TEMP;
Obviously each gets assigned as :ID, :NAME :QUANTITY and :DISC in apex.
Seeing as you are using Tabular form I suggest you ensure that the following is set.
On the procedure (in processing), Ensure you have the Tabular form selected.
Ensure the Condition "When button is pressed" is set to use the button you want to assign this process to.
in Oracle update clause should ALWAYS have where clause, because oracle will update all data in the table without the WHERE clause.
The cannot insert null error occurs when you are trying to insert in one of the table attributes NULL, where parameter set to NOT NULL, so in your case try to use NVL function, to avoid this issue, I ques that the NAME atribute should not be null.
try to modify your code like this:
update SALES_TEMP
set QUANTITY_TO_SELL = :QUANTITY,
DISCOUNT = :DISC,
NAME = nvl(:NAME,'empty')
where ID = :ID;
in this case it will update only one column.
The Oracle/PLSQL NVL function lets you substitute a value when a null value is encountered.

Correct this sql statement for Insert into, select, delete

INSERT INTO Checkout(ProductID, MemberID, Quantity)
SELECT ProductID, MemberID, Quantity
FROM Cart
WHERE (MemberID = MemberID)
DELETE FROM CART WHERE (MemberID = MemberID)
The sql statement is workable until the Select, WHERE part but once I add the delete statement then the error (syntax error missing operator in query expression) comes out. The second MemberID is a value I gave for first MemberID parameter. Please help me to solve this as after I transfer the data from first table to second table then I need to delete the data from first table.
[Edit] Thanks to you all suggestions and now I realized that for WHERE (MemberID = MemberID)
will import entire table to new table and this statement also will delete the entire table contents. What can I do to make sure that the sql statement only delete the particulars members item?
Main Page>Member login page>Buy something>Item stored in shopping cart database (with member id)>display only particular member's bought item in shopping cart> proceed to checkout(only display that member item, delete shopping cart item)
The problem is with the second "MemberID". This needs to be a constant or have a variable name that doesn't conflict with the field name. A number of techniques for disambiguation are shown in a related SO post: How do you avoid column name conflicts?
You didn't mention what version of SQL Server you're using - but you might be able to use the OUTPUT clause for the DELETE statement to achieve what you're looking for. The OUTPUT clause was introduced in SQL Server 2005, so if you're on 2005 or newer, this code snippet should work for you:
Try this:
DELETE FROM dbo.CART
OUTPUT deleted.ProductID, deleted.MemberID, deleted.Quantity
INTO dbo.Checkout(ProductID, MemberID, Quantity)
WHERE MemberID = #MemberID
Basically this runs the DELETE statement against your dbo.Cart table, and it captures what rows have been deleted; those are then in turn inserted into the dbo.Checkout table.
Also - that condition in the WHERE clause seems quite funny - basically, this will select and thus delete all rows from your table......
Update: I'm assuming you somehow store the relevant member's ID in #MemberID and use that to select the rows to delete from the dbo.Cart table..
Store your passing data to a newly declared variable and use that variable to everywhere as below, this will work fine, thanks
DECLARE #PassedMemberID INT
SET #PassedMemberID = MemberID --Store your passing MemberID here for later use
INSERT INTO Checkout(ProductID, MemberID, Quantity)
SELECT ProductID, MemberID, Quantity
FROM Cart
WHERE (MemberID = #PassedMemberID)
DELETE FROM CART WHERE (MemberID = #PassedMemberID)