How to remove a record from a table valued parameter? - sql

I would like to know how to remove a value from a Table Valued Parameter in SQL?
Is this even possible? If not, what would be the workaround?
Please see my code below and note the comments. The comments portion is where I would like to insert a line that would allow me to remove a record from the TVP #Record_NumList
Once that record is removed, I then proceed to insert a new one (basically, I don't want to execute the stored procedure on an existing record).
DECLARE #RecordID int
DECLARE #RecordID_NumList as Le_NumberList
DECLARE cur_DelRec CURSOR
FOR
SELECT DBRecordID from <<table_name>>
OPEN cur_DelRec
FETCH NEXT from cur_DelRec into #RecordID
INSERT into #RecordID_NumList(#RecordID)
WHILE ##FETCH_STATUS = 0
BEGIN
exec <<stored_procedure>> #RecordID_NumList
/* I'm stuck here: */
/* Need to remove from the existing record
from #RecordID_NumList */
FETCH NEXT FROM cur_DelRec into #RecordID
INSERT into #RecordID_NumList(#RecordID)
END
CLOSE cur_DelRec
DEALLOCATE cur_DelRec
On a more general level, is a TVP a collection? Let's say I chose not to delete it from #Record_NumList. What would happen in that case?
I apologize, but I'm still learning SQL and any help would be greatly appreciated!
Ray

Table valued parameters works just like a regular table. You should be able to just do something like this:
delete from #Record_numList where [field] = [value]

Related

Redshift Cursor

I am trying to get maximum length of each column of a table in Redshift database with this query:
select MAX(LEN(Trim(col1)))mx_len from tbl1;
and insert result into a tmp table like:
tbl1 col1 50
For this, I am trying to write a cursor in redshift to fetch column name one by one and insert data into tmp table. I am getting column names from following query:
select columnname from information_schema.columns where table_name = 'tbl1'
but unable to write a cursor, can anyone help me with this. Thanks in advance.
You haven't describes how you are trying to declare a cursor so it is a little hard to know what the problem is. So I'll describe a generic path to making a cursor and fetching from it.
First a cursor only lives for the duration of the transaction so you must begin and keep open a transaction.
BEGIN;
Next you need to declare the cursor and what data it will contain.
DECLARE <cursor_name> CURSOR FOR SELECT X, Y, Z FROM ...
Then you need to fetch a row from the cursor.
FETCH FORWARD 1 FROM <cursor_name>;
Then get the next row.
FETCH NEXT FROM <cursor_name>;
And on and on. When done close the cursor and end the transaction.
CLOSE <cursor_name>;
END;
Is this what you are doing? Is this not working?

How to create a trigger to decrease a counter, what's wrong with my trigger?

I need to decrease a counter in a table schedules, when there was an insert in enrollments table:
CREATE TRIGGER [UpdateEnrollmentsTrigger]
ON [TBLENROLLMENT_ENR]
FOR INSERT
AS
BEGIN
DECLARE #ScheduleCode NVARCHAR
DECLARE #TotalSlots INT
IF EXISTS(SELECT SCH_CODE FROM inserted)
BEGIN
SELECT #ScheduleCode = SCH_CODE FROM inserted
SELECT #TotalSlots = SCH_TOTALSLOTS FROM TBLSCHEDULES_SCH
WHERE SCH_CODE = #ScheduleCode
UPDATE TBLSCHEDULES_SCH
SET SCH_FREESLOTS = #TotalSlots - 1
WHERE SCH_CODE = #ScheduleCode
END
END
When I trying to create this trigger, the query window of VS12 says:
SQL46010 :: Incorrect syntax near ].
Thanks in advance.
The specific error is because you are using FOR INSERT instead of AFTER INSERT, but there are other things that you should improve on your trigger.
First of all, always, always write the length of a NVARCHAR, leaving it blank will behave differently depending where it's used. So replace DECLARE #ScheduleCode NVARCHAR with DECLARE #ScheduleCode NVARCHAR(n), where n is the required length.
I'm also not sure why you are doing the IF EXISTS since it's reading the INSERTED pseudo table, that it's bound to have records because the trigger was fired.
Another thing to improve is that you are assuming that only one row was inserted, as you are storing it on a variable, that's wrong and it will behave incorrectly if you insert more than just one row.
Oh, I almost forgot, you should also always specify the schema, for instance: CREATE TRIGGER [UpdateEnrollmentsTrigger] ON [TBLENROLLMENT_ENR] should be CREATE TRIGGER dbo.[UpdateEnrollmentsTrigger] ON dbo.[TBLENROLLMENT_ENR] (using the correct schema, of course)

Print out cursor values

I am modifying a stored procedure which is using a cursor, I want to be able to print out or output the values from the cursor that is inserting into a table but am having a hard time trying to figure out how to do this. I need to check all the values for example that get inserted in the orders table by this stored procedure.
I cant do
Print #prodId, #orderQuantity, #orderDate, #orderLocationId, #shipmentId, #shipmentDate
How can I output/print all the values the cursor has in these columns for each record it goes through? An example with how to do this in code would be appreciated.
If using MS SQL Server then you could use RAISERROR. On this link ypu have a good explanation with samples on how to use them and differences between them. Check out RAISERROR sintaxis here
Try
PRINT STR(#prodId) + STR(#orderQuantity) + STR(#orderDate) + STR(#orderLocationId) + STR(#shipmentId) + STR(#shipmentDate)
If that doesnt work then (for the non int variables) try
CAST(#orderDate as NVARCHAR(MAX))
Also look at this article.
http://msdn.microsoft.com/en-us/library/ms187928.aspx
Best of Luck
You can capture & store the inserted rows in the correct order by outputting them into a temp table with an identity;
create table #inserted(insertorder int identity(0,1), prodId int, orderQuantity int ... <matches inserted row>)
--cursor loop
insert destination_table(prodId, orderQuantity, ...)
output inserted.* into #inserted /*output inserted.* will just select it */
values #prodId, #orderQuantity ...
--end loop
--inserted rows;
select * from #inserted order by insertorder
When using PRINT, a simple trick instead of STR() which doesn't exist, or CONVERT(varchar(50), #orderQuantity)
Which is cumbersome, just use RTRIM(#orderQuantlty) for fast implicit conversion from numeric to string.

Execute SQL statements while looping a table

I want to create a table with a few records in it and then run a set of sql statements for every record in that table. I would use the data in the table to set values in the sql statement.
This should allow me to write the SQL just once and then run it for whatever data I put in the table.
But, I'm not sure how to go about doing this. Should I use a cursor to loop the table? Some other way?
Thanks for any help or advice you can give me.
CURSOR will have an overhead associated with it, but can be a good method to walk through your table. They are not a totally unnecessary evil and have their place.
With the limited information that WilliamB2 provided, it sounds like a CURSOR set may be a good solution for this problem to walk through his data and generate the multiple downstream INSERTs.
Yes you can use a cursor. You can also use a while loop
declare #table as table(col1 int, col2 varchar(20))
declare #col1 int
declare #col2 varchar(50)
declare #sql varchar(max)
insert into #table
SELECT col1, col2 FROM OriginalTable
while(exists(select top 1 'x' from #table)) --as long as #table contains records continue
begin
select top 1 #col1=col1, #col2=col2 from #table
SET #sql = 'INSERT INTO Table t VALUES('+cast(#col1 as varchar)+')'
delete top (1) from #table --remove the previously processed row. also ensures no infinite loop
end
I think cursor has an overhead attached to it.
With this second approach you are not working on the original table
Maybe you could use INSERT...SELECT instead of the loop:
INSERT INTO target_table
SELECT
some_col,
some_other_col,
'Some fixed value',
NULL,
42,
you_get_the_idea
FROM source_table
WHERE source_table.you_get_the_idea = 1
The columns on your SELECT should match the structure of the target table (you can omit an int/identity pk like id if you have one).
If the best option is this or the loop depends on how many tables you want to populate inside the loop. If it's just a few, I usually stick with INSERT...SELECT.

SQL session/connection variables

I'm trying to find some equivalent to session variables in SQL. I want to be able to store and retrieve just a number but each connection to the database has a different number. It needs to persist from one batch to the next on the same connection.
I did have a solution that used a global cursor like this.
IF (SELECT CURSOR_STATUS('global','ChangeSet')) >= 0
BEGIN --Close and deallocate the cursor
Close ChangeSet
DEALLOCATE ChangeSet
END
--Create a new cursor
DECLARE ChangeSet CURSOR GLOBAL STATIC FOR
SELECT ChangeSet = #ChangeSet
--Open the cursor
OPEN ChangeSet
Each connection would have a different cursor so it worked, but this is not usable inside of a view. I guess if somebody can show me how to read this in a view that would be cool too.
I'm using MS SQL Server btw.
The CONTEXT_INFO property may be what you're looking for - it enables you to set and read a connection-specific binary value.
You could encode your numeric value to binary and store it in this property.
Starting from SQL 2016
EXEC sys.sp_set_session_context #key = N'language', #value = 'English';
SELECT SESSION_CONTEXT(N'language');
A temporary table survives a batch (including go). It's still connection specific:
create table #temp (val float)
insert #temp values (3.14)
go
select * from #temp