How to pass an array of numbers to a stored procedure? - sql

I would like to write a stored procedure that can receive one or more employee IDs and return data based on these IDs. The number of employee IDs will vary every time the sproc is called.
How can I write a the stored procedure to return the Branch Address of every employee ID passed in, where the number of employee IDs will be variable?
Employee Table
ID
Name
Branch_ID
Branch Table
ID
Name
Address

If you have an SQL 2008 or higher running then I'd suggest using table types. Then you can pass a table to the stored procedure. Here is a little example I made to demonstrate just that.
create database tmpDB;
go
use tmpDB;
go
create table tblEmployee
(
ID int identity(1, 1)
primary key
not null,
Name nvarchar(200),
Branch_ID int
);
go
insert into dbo.tblEmployee
(Name, Branch_ID)
values (N'Brian', 1),
(N'Mary', 1),
(N'Peter', 2),
(N'Sonya', 2),
(N'Roland', 1),
(N'Tom', 3),
(N'Sam', 3),
(N'Ryan', 3),
(N'Julia', 3),
(N'Tim', 1),
(N'Eva', 2);
go
select *
from dbo.tblEmployee;
go
create type typEmployee as table
(
Name nvarchar(200),
BranchID int
);
go
grant exec on type::typEmployee to public;
go
create procedure spInsertEmployees
(
#NewEmployees typEmployee readonly
)
as
begin
merge tblEmployee as target
using
(
select Name,
BranchID
from #NewEmployees
) as source (Name, BranchID)
on (
target.Name = source.Name
and target.Branch_ID = source.BranchID
)
when not matched then
insert (Name, Branch_ID)
values (
source.Name,
source.BranchID
);
end;
go
grant execute on spInsertEmployees to public;
go
declare #tmpTable typEmployee;
insert into #tmpTable
(Name, BranchID)
values (N'NewEmployee', 1),
(N'NewEmployee', 2),
(N'NewEmployee', 3),
(N'Sonya', 2),
(N'Tim', 1);
exec dbo.spInsertEmployees
#NewEmployees = #tmpTable;
select *
from dbo.tblEmployee;
go
use master;
go
drop database tmpDB;
go

What we do is just pass in a delimited list. So 1,2,3,42,55,6666 with nvarchar(max).
Then we have a user defined function that returns a table and we join on that.
Google search on t sql split string using delimiter and you'll find examples.
select * from dbo.udfSplit(#inputfromparameters, ",") inner join ....

Related

How can I return the top N most recently inserted records from a table? [duplicate]

I have created table like below:
create table EmployeeDetails
(
id int,
name varchar(50),
designation varchar(50),
ReportingTo int
)
And inserted rows like this:
insert into EmployeeDetails values(1, 'A', 'Developer', 3)
insert into EmployeeDetails values(5, 'E', 'CEO', 5)
insert into EmployeeDetails values(2, 'B', 'Developer', 3)
insert into EmployeeDetails values(3, 'C', 'Manager', 4)
insert into EmployeeDetails values(4, 'D', 'S.Manager', 5)
My question is: how can I identify the last inserted row in the table?
Used queries:
select IDENT_CURRENT('EmployeeDetails')
Select SCOPE_IDENTITY()
But I still didn't find the answer.
Replies are always welcome
You have a fundamental misunderstanding of tables in relational databases. They represent unordered sets. So, there is no "last row" in a table. The information on the ordering of rows has to be included when you create the table and/or load data into it.
In SQL Server, the simplest method is an identity column. That is why many tables are defined as:
create table EmployeeDetails (
id int identity primary key,
name varchar(50),
designation varchar(50),
ReportingTo int
);
You can also add default insertion time columns:
create table EmployeeDetails (
id int identity primary key,
name varchar(50),
designation varchar(50),
ReportingTo int,
CreatedAt datetime default gettime()
);
However, you can have multiple rows with the same datetime value.
You also can use rowversion like below,if you add a column
CREATE TABLE MyTest (myKey int
,myValue int, RV rowversion);
GO
INSERT INTO MyTest (myKey, myValue) VALUES (1, 0);
GO
INSERT INTO MyTest (myKey, myValue) VALUES (2, 0);
select * from mytest order by rv desc
Note:
This always give the last row inserted/Updated
References:
rowversion
Add fields of type datetime with name CreateDate and UpdateDate in your table, when you insert record in your table set their value for getdate()
After that you can run queries:
Select top 10 * from YourTable Order By CreateDate DESC
Or for last updated
Select top 10 * from YourTable Order By UpdateDate DESC
Please find my answer as below. Hope this may help you.
Add one more column to store record creation date/time as below.
create table EmployeeDetails
(
id int,
name varchar(50),
designation varchar(50),
ReportingTo int,
CreatedOn datetime
)
After table creation and inserting records write/execute query (here inner query is used) as below
select
*
from EmployeeDetails
where CreatedOn = (select max(CreatedOn) from EmployeeDetails )

How to compare String Variable with Integer

I have this table structure and and some sample data. I want return data for multiple ids via parameter. I have declared a parameter string and now I want to compare it with the column but it ain't allowing because ID is integer.
Can anybody give me any help here ?
CREATE TABLE EMPLOYEE
(
ID INT,
EMPLOYEE_NAME VARCHAR(50)
);
INSERT INTO EMPLOYEE VALUES (1, 'Isaac Frempong');
INSERT INTO EMPLOYEE VALUES (2, 'Eric Ortizz');
DECLARE #StrID VARCHAR(20) = '1, 2'
SELECT * FROM EMPLOYEE
WHERE ID = #StrID
SELECT * FROM EMPLOYEE
WHERE #StrID+',' LIKE '%'+cast(ID as varchar(20))+'%,'
Pretty bad performance as it will need to do a table scan but safe enough.
Generally though, your list of IDs should be a table variable you can do a proper JOIN or IN with
The easiest solution is to use dynamic SQL
DECLARE #sql VARCHAR(1000) = 'SELECT * FROM EMPLOYEE WHERE ID IN (' + #StrID + ')';
EXEC(#sql);
For SQL Server 2017+ you could use STRING_SPLIT a table-valued function that splits a string into rows of substrings
CREATE TABLE EMPLOYEE
(
ID INT,
EMPLOYEE_NAME VARCHAR(50)
);
INSERT INTO EMPLOYEE VALUES (1, 'Isaac Frempong');
INSERT INTO EMPLOYEE VALUES (2, 'Eric Ortizz');
DECLARE #StrID VARCHAR(20) = '1, 2'
SELECT * FROM EMPLOYEE
WHERE ID IN (SELECT value FROM STRING_SPLIT (#StrID,','))
Refer this working fiddle
Create a user defined table type and pass it as a parameter.
CREATE TYPE [UDT_INTIDS] AS TABLE(
[ID] [int] NOT NULL
)
GO
-- create a table value
DECLARE #IDs [UDT_INTIDS];
INSERT #IDs VALUES (1),(2);
-- search using table value.
SELECT e.*
FROM EMPLOYEE e
WHERE e.ID IN (SELECT p.ID FROM #IDs p);
-- or
SELECT e.*
FROM EMPLOYEE e
JOIN #IDs p ON e.ID = p.ID;
See https://learn.microsoft.com/en-us/sql/relational-databases/tables/use-table-valued-parameters-database-engine?view=sql-server-2017 for more details.
You can use the Cast in SQL-Server to cast it to the appropriate datatype. Source Here
WHERE CAST(ID AS VARCHAR(20)) = #StrID
Alternatively: You can use CONVERT function.
WHERE CONVERT(VARCHAR(20), ID) = #StrID

Insert into a Informix table or update if exists

I want to add a row to an Informix database table, but when a row exists with the same unique key I want to update the row.
I have found a solution for MySQL here which is as follows but I need it for Informix:
INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE name="A", age=19
You probably should use the MERGE statement.
Given a suitable table:
create table table (id serial not null primary key, name varchar(20) not null, age integer not null);
this SQL works:
MERGE INTO table AS dst
USING (SELECT 1 AS id, 'A' AS name, 19 AS age
FROM sysmaster:'informix'.sysdual
) AS src
ON dst.id = src.id
WHEN NOT MATCHED THEN INSERT (dst.id, dst.name, dst.age)
VALUES (src.id, src.name, src.age)
WHEN MATCHED THEN UPDATE SET dst.name = src.name, dst.age = src.age
Informix has interesting rules allowing the use of keywords as identifiers without needing double quotes (indeed, unless you have DELIMIDENT set in the environment, double quotes are simply an alternative to single quotes around strings).
You can try the same behavior using the MERGE statement:
Example, creation of the target table:
CREATE TABLE target
(
id SERIAL PRIMARY KEY CONSTRAINT pk_tst,
name CHAR(1),
age SMALLINT
);
Create a temporary source table and insert the record you want:
CREATE TEMP TABLE source
(
id INT,
name CHAR(1),
age SMALLINT
) WITH NO LOG;
INSERT INTO source (id, name, age) VALUES (1, 'A', 19);
The MERGE would be:
MERGE INTO target AS t
USING source AS s ON t.id = s.id
WHEN MATCHED THEN
UPDATE
SET t.name = s.name, t.age = s.age
WHEN NOT MATCHED THEN
INSERT (id, name, age)
VALUES (s.id, s.name, s.age);
You'll see that the record was inserted then you can:
UPDATE source
SET age = 20
WHERE id = 1;
And test the MERGE again.
Another way to do it is create a stored procedure, basically you will do the INSERT statement and check the SQL error code, if it's -100 you go for the UPDATE.
Something like:
CREATE PROCEDURE sp_insrt_target(v_id INT, v_name CHAR(1), v_age SMALLINT)
ON EXCEPTION IN (-100)
UPDATE target
SET name = v_name, age = v_age
WHERE id = v_id;
END EXCEPTION
INSERT INTO target VALUES (v_id, v_name, v_age);
END PROCEDURE;

sql procedure auto iincrement if exist

procedure [dbo].[InsertSortCode] (
#Sortcode varchar(25)
, #verbiage varchar(200) )
as
begin
SET IDENTITY_INSERT appmaster on
insert into AppMaster(MainID,SortCode) values (
(select MAX(mainid)
from AppMaster) + 1, #Sortcode )
SET IDENTITY_INSERT appmaster off
insert into Verbiage(MenueID,verbiage) values (
(select MAX(mainid)
from AppMaster), #verbiage )
the above is my stored procedure it is working perfectly fine but there is an error if there is no data in the database
the problem is with max function ,if the is no data in database
it cannot max out the id it works only if there is already some data
with its id in that databse
need to figure out how to use the exist statement on this SP so that it can work with both empty table and filled table
You can try following query:-
insert into AppMaster(MainID,SortCode) values (
(select ISNULL(MAX(mainid),0)
from AppMaster) + 1, #Sortcode )
So if MAX(mainid) is null it will return as 0 and add 1 to that.

Set variable value to array of strings

I want to set a variable as a string of values. E.g.
declare #FirstName char(100)
select #FirstName = 'John','Sarah','George'
SELECT *
FROM Accounts
WHERE FirstName in (#FirstName)
I'm getting a syntax error in the line select #FirstName = 'John','Sarah','George':
Incorrect syntax near ','
Is there any way I can set the variable with many values?
declare #tab table(FirstName varchar(100))
insert into #tab values('John'),('Sarah'),('George')
SELECT *
FROM #tab
WHERE 'John' in (FirstName)
You're trying to assign three separate string literals to a single string variable. A valid string variable would be 'John, Sarah, George'. If you want embedded single quotes between the double quotes, you have to escape them.
Also, your actual SELECT won't work, because SQL databases won't parse the string variable out into individual literal values. You need to use dynamic SQL instead, and then execute that dynamic SQL statement. (Search this site for dynamic SQL, with the database engine you're using as the topic (as in [sqlserver] dynamic SQL), and you should get several examples.)
-- create test table "Accounts"
create table Accounts (
c_ID int primary key
,first_name varchar(100)
,last_name varchar(100)
,city varchar(100)
);
insert into Accounts values (101, 'Sebastian', 'Volk', 'Frankfurt' );
insert into Accounts values (102, 'Beate', 'Mueller', 'Hamburg' );
insert into Accounts values (103, 'John', 'Walker', 'Washington' );
insert into Accounts values (104, 'Britney', 'Sears', 'Holywood' );
insert into Accounts values (105, 'Sarah', 'Schmidt', 'Mainz' );
insert into Accounts values (106, 'George', 'Lewis', 'New Jersey' );
insert into Accounts values (107, 'Jian-xin', 'Wang', 'Peking' );
insert into Accounts values (108, 'Katrina', 'Khan', 'Bolywood' );
-- declare table variable
declare #tb_FirstName table(name varchar(100));
insert into #tb_FirstName values ('John'), ('Sarah'), ('George');
SELECT *
FROM Accounts
WHERE first_name in (select name from #tb_FirstName);
SELECT *
FROM Accounts
WHERE first_name not in (select name from #tb_FirstName);
go
drop table Accounts;
go
A quick way to turn your varchar variable to a table (array of values) is to have your FirstName variable as a whole varchar first and then use the STRING_SPLIT method.
declare #FirstName varchar(100)
select #FirstName = 'John,Sarah,George'
SELECT *
FROM Accounts
WHERE FirstName in (SELECT * FROM STRING_SPLIT(#FirstName, ','))
In SQL you can not have a variable array.
However, the best alternative solution is to use a temporary table.
I just want to extend #Code Save's answer
--collection table is required, since we cannot use directly arrays in TSQL
declare #CollectionTable table(FirstName varchar(100))
insert into #CollectionTable values('John'),('Sarah'),('George')
SELECT * FROM TargetTable
WHERE Name IN (SELECT * FROM #CollectionTable)
In this way we can use the result from the SELECT statement from our #CollectionTable to be evaluated in the IN operator. And of course we can re-use the #CollectionTable as many times as we need.