Update Trigger conditional values - sql-server

I have been searching around stackoverflow but I have not found what I'm looking for.
I have a Sql Server Database. One table with a field "Priority" I would like to update on every insert or update.
The problem is that I want to perform a Priority pile using this rules:
1.-If the value I try to insert has a prority value that already exists then every consecutive row in the table must change its priority value adding 1.
2.-If the value I try to insert has a priority that not exists then the trigger does nothing.
This is the trigger I haver built:
ALTER trigger [Priority]
on [dbo].[TBL_PILA]
after insert, update
AS
declare #priority int;
declare #reg_id int;
SELECT #reg_id =i.id from inserted i;
SELECT #priority =PRIORITY from TBL_PILA where ID =#reg_id
-- perform update here in TBL_PILA table
UPDATE TBL_PILA SET PRIORITY=PRIORITY+1 WHERE ID <>#reg_id AND PRIORITY>=#priority
GO
Edit: As Suggestions, I change the trigger body like this:
ALTER trigger [Priority]
on [dbo].[TBL_PILA]
after insert, update
if exists (select *
from inserted i join TBL_PILA m
on i.ID = m.ID
)
update TBL_PILA set PRIORITY = PRIORITY + 1
where exists (select * from inserted i
join TBL_PILA m
on i.ID = m.ID
where m.PRIORITY>=i.PRIORITY)
Now I have a new problem: the priority value inserted is affected by the trigger and it is added 1 too.
Does anybody knows how to increase priority values only affecting some range as I explained below?
The problem is whenever exists a few consecutive values and one not consecutive value the trigger must stops.
Example
Priority 1 2 4 5 6 8
If I try to insert a row with priority=3 the result should be:
1 2 3 4 5 6 8
Then If I try to insert a row with priority=4 then the result should be:
1 2 3 4 (inserted value) 5 (4+1) 6 (5+1) 7 (6+1) 8
But using the trigger I built I get this: 1 2 3 4 5 6 7 9 (8+1)

Related

Inserting a row in a table depending on the values of columns in a different table in MSSQL

I have a table called reportValues:
id isNew isExclusive isPremium
10 1 1 0
11 0 0 1
12 1 0 1
and I have a table called productProperties
isNew has propertyId of 1, isExclusive has a propertyId of 2, and isPremium has a propertyId of 3.
id propertyId
10 1
10 2
11 3
12 1
12 3
I need to add rows into productProperties depending on the boolean values of table reportValues, how do you do this with a stored procedure? I am thinking you need some kind of if statement, but I couldn't find an example.
I think you're looking for something like this. The boolean values are unpivoted using CROSS APPLY and assigned 1,2,3 propertyId's. Then the converted values are inserted WHERE the boolean property is TRUE, i.e. v.property=1. The following stored procedure inserts into the productProperties table and checks to make sure the values don't already exists. Maybe that's not necessary? It could be commented out or deleted.
drop proc if exists dbo.productPropertiesInsert;
go
create proc dbo.productPropertiesInsert
as
set nocount on;
insert productProperties
select v.id, v.propertyId
from reportValues rv
cross apply (values (1, rv.id, rv.isNew),
(2, rv.id, rv.isExclusive),
(3, rv.id, rv.isPremium))
v(propertyId, id, property)
where v.property=1
/* optional code? */
and not exists(select 1
from productProperties p_in
where v.id=p_in.id
and v.propertyId=p.propertyId);
go

Trigger in SQL server?

I have class table which references student table.
I write a trigger to +1 amount of exellent_eng when insert >=8 score of English subject but it has error:
Msg 4104, Level 16, State 1, Procedure tr_addExellentEnglishStudent, Line 3 [Batch Start Line 1]
The multi-part identifier "x.exellent_Eng" could not be bound.
I'm using SSMS.
CREATE TRIGGER tr_addExellentEnglishStudent ON dbo.dbo_student AFTER INSERT AS
BEGIN
UPDATE dbo.dbo_class
SET x.exellent_Eng += 1
FROM dbo.dbo_class x
JOIN dbo.dbo_student s ON s.class_id = x.class_id
JOIN dbo.dbo_score c ON c.student_id = s.student_id
WHERE (c.subject_id = 1 AND c.score_id >= 8)
END
Few points to correct here:
I don't think you want your trigger on the dbo_student table, because when you first insert a student they won't have any scores. I think you wanted the trigger on adding a new dbo_score record?
As noted in the comments if you alias the table you are updating you should use the notation update <alias> e.g. update x
You don't prefix the column(s) to update with the table name/alias, SQL Server knows which table you are updating.
You probably want to restrict the update to students affected by using the Inserted pseudo-table.
CREATE TRIGGER tr_addExellentEnglishStudent ON dbo.dbo_score
AFTER INSERT AS
BEGIN
UPDATE x SET
exellent_Eng += 1
FROM dbo.dbo_class x
JOIN dbo.dbo_student s ON s.class_id = x.class_id
JOIN dbo.dbo_score c ON c.student_id = s.student_id
WHERE (c.subject_id = 1 AND c.score_id >= 8)
and c.id in (select id from Inserted)
END
Note: this doesn't consider any of the edge cases which might arise e.g. if you update an existing score from 7 to 8 then technically you would want to increase your excellent_Eng result. Similarly if you delete a score or update it from 8 to 7 you would want to decrease it. For these reasons if can be simpler to re-calculate the absolute result rather than making incremental changes.

Swap values in a column in SQL Server table

I am trying to update my tables data(1=>3, 2=>1, 3=>2) by swapping them using below queries.
/* Temporarily set 1 to a dummy unused value of 11
so they are disambiguated from those set to 1 in the next step */
update <tablename>
set id = 11
where id = 1
update <tablename>
set id = 1
where id = 2
update <tablename>
set id = 2
where id = 3
update <tablename>
set id = 3
where id = 11
Wondering if I can optimize my script.
You can just use case. Conceptually the operation happens "all at once" so there's no need to use a fourth dummy value as in your sequential approach.
UPDATE YourTable
SET ID = CASE ID WHEN 1 THEN 3
WHEN 2 THEN 1
WHEN 3 THEN 2
END
WHERE ID IN (1,2,3)
Though changing ids is unusual as they should generally be immutable.

SQL Deletion of only one field with where clause

I have a table thus
ID stuff1 stuff2
1 10 cool
2 4 poor
3 8 cool
4 1 sucks
I need an sql to delete only 10 in row 1
I used->>> delete stuff1 from mytable where ID=1
This works on access db but does not work on sql server
How do I do this on SQL server???
Are you trying to delete the row, or do you just want to remove the values from column stuff1?
In case you want to delete the row:
DELETE FROM mytable where ID = 1
In case you just want to remove the value of stuff1:
-- to set it to null
UPDATE mytable SET stuff1 = NULL WHERE ID = 1
-- to set it to zero
UPDATE mytable SET stuff1 = 0 WHERE ID = 1
By delete one field, I'm guessing you really mean null the column value:
UPDATE mytable
SET stuff1 = null
WHERE ID=1
DELETE works on whole rows, not individual columns.

T-SQL Grouping Sets of Information

I have a problem which my limited SQL knowledge is keeping me from understanding.
First the problem:
I have a database which I need to run a report on, it contains configurations of a users entitlements. The report needs to show a distinct list of these configurations and a count against each one.
So a line in my DB looks like this:
USER_ID SALE_ITEM_ID SALE_ITEM_NAME PRODUCT_NAME CURRENT_LINK_NUM PRICE_SHEET_ID
37715 547 CultFREE CultPlus 0 561
the above line is one row of a users configuration, for every user ID there can be 1-5 of these lines. So the definition of a configuration is multiple rows of data sharing a common User ID with variable attributes..
I need to get a distinct list of these configurations across the whole table, leaving me just one configuration set for every instance where > 1 has that configuration and a count of instances of that configuration.
Hope this is clear?
Any ideas?!?!
I have tried various group by's and unions, also the grouping sets function to no avail.
Will be very greatful if anyone can give me some pointers!
Ouch that hurt ...
Ok so problem:
a row represents a configurable line
users may be linked to more than 1 row of configuration
configuration rows when grouped together form a configuration set
we want to figure out all of the distinct configuration sets
we want to know what users are using them.
Solution (its a bit messy but the idea is there, copy and paste in to SQL management studio) ...
-- ok so i imported the data to a table named SampleData ...
-- 1. import the data
-- 2. add a new column
-- 3. select all the values of the config in to the new column (Configuration_id)
--UPDATE [dbo].[SampleData]
--SET [Configuration_ID] = SALE_ITEM_ID + SALE_ITEM_NAME + [PRODUCT_NAME] + [CURRENT_LINK_NUM] + [PRICE_SHEET_ID] + [Configuration_ID]
-- 4. i then selected just the distinct values of those and found 6 distinct Configuration_id's
--SELECT DISTINCT [Configuration_ID] FROM [dbo].[SampleData]
-- 5. to make them a bit easier to read and work with i gave them int values instead
-- for me it was easy to do this manually but you might wanna do some trickery here to autonumber them or something
-- basic idea is to run the step 4 statement but select into a new table then add a new primary key column and set identity spec on it
-- that will generate u a bunch of incremental numbers for your config id's so u can then do something like ...
--UPDATE [dbo].[SampleData] sd
--SET Configuration_ID = (SELECT ID FROM TempConfigTable WHERE Config_ID = sd.Configuration_ID)
-- at this point you have all your existing rows with a unique ident for the values combined in each row.
-- so for example in my dataset i have several rows where only the user_id has changed but all look like this ...
--SALE_ITEM_ID SALE_ITEM_NAME PRODUCT_NAME CURRENT_LINK_NUM PRICE_SHEET_ID Configuration_ID
--54101 TravelFREE TravelPlus 0 56101 1
-- now you have a config id you can start to work on building sets up ...
-- each user is now matched with 1 or more config id
-- 6. we use a CTE (common table expression) to link the possibles (keeps the join small) ...
--WITH Temp (ConfigID)
--AS
--(
-- SELECT DISTINCT SD.Configuration_Id --SD2.Configuration_Id, SD3.Configuration_Id, SD4.Configuration_Id, SD5.Configuration_Id,
-- FROM [dbo].[SampleData] SD
--)
-- this extracts all the possible combinations using the CTE
-- on the basis of what you told me, max rows per user is 6, in the result set i have i only have 5 distinct configs
-- meaning i gain nothing by doing a 6th join.
-- cross joins basically give you every combination of unique values from the 2 tables but we joined back on the same table
-- so its every possible combination of Temp + Temp (ConfigID + ConfigID) ... per cross join so with 5 joins its every combination of
-- Temp + Temp + Temp + Temp + Temp .. good job temp only has 1 column with 5 values in it
-- 7. uncomment both this and the CTE above ... need to use them together
--SELECT DISTINCT T.ConfigID C1, T2.ConfigID C2, T3.ConfigID C3, T4.ConfigID C4, T5.ConfigID C5
--INTO [SETS]
--FROM Temp T
--CROSS JOIN Temp T2
--CROSS JOIN Temp T3
--CROSS JOIN Temp T4
--CROSS JOIN Temp T5
-- notice the INTO clause ... this dumps me out a new [SETS] table in my db
-- if i go add a primary key to this and set its ident spec i now have unique set id's
-- for each row in the table.
--SELECT *
--FROM [dbo].[SETS]
-- now here's where it gets interesting ... row 1 defines a set as being config id 1 and nothing else
-- row 2 defines set 2 as being config 1 and config 2 and nothing else ... and so on ...
-- the problem here of course is that 1,2,1,1,1 is technically the same set as 1,1,1,2,1 from our point of view
-- ok lets assign a set to each userid ...
-- 8. first we pull the distinct id's out ...
--SELECT DISTINCT USER_ID usr, null SetID
--INTO UserSets
--FROM SampleData
-- now we need to do bit a of operating on these that's a bit much for a single update or select so ...
-- 9. process findings in a loop
DECLARE #currentUser int
DECLARE #set int
-- while theres a userid not linked to a set
WHILE EXISTS(#currentUser = SELECT TOP 1 usr FROM UserSets WHERE SetId IS NULL)
BEGIN
-- figure out a set to link it to
SET #set = (
SELECT TOP 1 ID
FROM [SETS]
-- shouldn't really do this ... basically need to refactor in to a table variable then compare to that
-- that way the table lookup on ur main data is only 1 per User_id
WHERE C1 IN (SELECT DISTINCT Configuration_id FROM SampleData WHERE USER_ID = #currentUser)
AND C2 IN (SELECT DISTINCT Configuration_id FROM SampleData WHERE USER_ID = #currentUser)
AND C3 IN (SELECT DISTINCT Configuration_id FROM SampleData WHERE USER_ID = #currentUser)
AND C4 IN (SELECT DISTINCT Configuration_id FROM SampleData WHERE USER_ID = #currentUser)
AND C5 IN (SELECT DISTINCT Configuration_id FROM SampleData WHERE USER_ID = #currentUser)
)
-- hopefully that worked
IF(#set IS NOT NULL)
BEGIN
-- tell the usersets table
UPDATE UserSets SET SetId = #set WHERE usr = #currentUser
set #set = null
END
ELSE -- something went wrong ... set to 0 to prevent endless loop but any userid linked to set 0 is a problem u need to look at
UPDATE UserSets SET SetId = 0 WHERE usr = #currentUser
-- and round we go again ... until we are done
END
SELECT
USER_ID,
SALE_ITEM_ID, ETC...,
COUNT(*) WhateverYouWantToNameCount
FROM TableNAme
GROUP BY USER_ID

Resources