Multiple values in one parameter in a stored procedure - sql-server

My stored procedure needs to insert multiple products in the [Order Details] table.
One OrderID = Many products.
I saw a code where you will create a temporary table like a list to store multiple values. But I don't know how to use it when the values is not pre-defined or is a user input.
--I want to input multiple ProductID in this temporary table
DECLARE #myOrders table (ID int)
INSERT INTO #myOrders ("")
--Then get data from the Products table and input the data in Order Details
INSERT INTO [Order Details] (ProductID)
SELECT ProductID From Products
WHERE ProductID IN (SELECT ID FROM #myOrders)
Sample pic of Order details

First you need to define type like following
CREATE TYPE ProductList AS TABLE
(
ProductId INT
)
GO
Then create your procedure like following
ALTER PROCEDURE USP_TEST_PROC (#OrderId INT,#Produt_Id_List ProductList READONLY)
AS
BEGIN
DECLARE #OrderDetails TABLE(OrderId INT, ProductID INT,UnitPrice DECIMAL(18,2),Quantity INT, Discount DECIMAL(18,2))
DECLARE #Products TABLE(ProductID INT,UnitPrice DECIMAL(18,2),Quantity INT, Discount DECIMAL(18,2))
INSERT INTO #OrderDetails (OrderId, ProductID,UnitPrice,Quantity, Discount)
SELECT #OrderId, ProductID,UnitPrice,Quantity,Discount FROM #Products WHERE ProductID IN (SELECT ProductId FROM #Produt_Id_List)
SELECT * FROM #OrderDetails
END
Then prepare table variable to put values like following
DECLARE #PList ProductList;
INSERT #PList VALUES (1),(2),(3)
Finally call procedure
EXEC USP_TEST_PROC 100,#PList
Thanks

Stored procedures accept table inputs in the form of table values parameters. Look at the documentation here
https://learn.microsoft.com/en-us/sql/relational-databases/tables/use-table-valued-parameters-database-engine
This includes an example also on how to invoke such a stored procedure.
You can directly use the TVP similar to a table variable (#myOrders in you sample) in the stored procedure body.
If you are looking to also call that stored procedure from ADO.NET, below article has a good description.
https://www.codeproject.com/Articles/39161/C-and-Table-Value-Parameters

Related

SQL parameter insert in temp table

I have ssrs report which receives multivalued parameter like we can check USA,India,Germany from the checkboxes
Parameter name is #country
What I need is I need to store the parameter in table in below format
Create table #tempcountry
(Name varchar(20))
Insert into #tempcountry values (#country)
What I basically need is table has to store values like
Name
USA
India
Germany
This is my requirement I am struck here can anyone help me out on this??
In this case the parameter must be a table typed one, passed in READ ONLY mode and having all the data inserted before in a table variable.
Example :
CREATE TYPE TYP_COUNTRIES AS TABLE (COUNTRY_NAME VARCHAR(100));
GO
The query report must be base on a function or a procedure :
CREATE FUNCTION dbo.F_T_MyQuery (#CTRY TYP_COUNTRIES READONLY)
RETURNS TABLE
AS
RETURN (SELECT *
FROM MyTable
WHERE Country_name IN (SELECT * FROM #CTRY);
GO
To use it :
DECLARE #Countries TYP_COUNTRIES;
INSERT INTO #Countries VALUES ('spain', 'italy', 'france')
SELECT *
FROM dbo.F_T_MyQuery (#Countries);

Checking whether value exists in results of a stored procedure

I have a stored procedure which returns a list of IDs for a particular set of generators I want to be able to then use the results of this stored procedure as part of another query.
Can I write a query like:
select * from table where id in (exec dbo.storedprocedurename)
Using table variable and JOIN you can achieve this. Store the procedure result into the table.
DECLARE #ProcOutput TABLE (Id INT);
INSERT INTO #ProcOutput (Id)
EXEC [dbo].[storedprocedurename]
SELECT T.*
FROM Table T
JOIN #ProcOutput O ON O.Id = T.Id
If the procedure returns multiple entries, according to the output you can re-design the table's schema.
If your output of procedure is 2 columns then you may try this:
INSERT INTO MyTable
(
Col1,
Col2
)
EXEC [dbo].[storedprocedurename]
GO
SELECT * FROM TABLE WHERE ID IN (SELECT Col1 from Mytable)

Query table-per-month data without dynamic SQL

A vendor, in their infinite wisdom, has decided to split a holidays dataset by month into separate tables i.e.
holidayPlanner.dbo.holiday_201802
holidayPlanner.dbo.holiday_201803
holidayPlanner.dbo.holiday_201804
holidayPlanner.dbo.holiday_201805
These tables are generated by the system as soon as an employee requests a holiday in the month. I can write a query that uses dynamic SQL to create a UNION query that I can work with.
Is there any way this can be done without dynamic SQL? Ideally, so I can create a table-valued-function to get the results?
you could use a table function that returns as the result the values obtained in each of the tables to be identified (you could do a search by months)
I leave the following example:
CREATE FUNCTION [dbo].[ufnHolidays]()
RETURNS #holidays TABLE
(
id int
)
AS
BEGIN
/* example data
CREATE TABLE #holiday_201802 (id int)
CREATE TABLE #holiday_201803 (id int)
CREATE TABLE #holiday_201804 (id int)
INSERT #holiday_201802 VALUES (1)
INSERT #holiday_201803 VALUES (2)
INSERT #holiday_201804 VALUES (3)
*/
IF OBJECT_ID('tempdb.dbo.#holiday_201802') IS NOT NULL
INSERT #holidays
SELECT id FROM #holiday_201802
IF OBJECT_ID('tempdb.dbo.#holiday_201803') IS NOT NULL
INSERT #holidays
SELECT id FROM #holiday_201803
IF OBJECT_ID('tempdb.dbo.#holiday_201804') IS NOT NULL
INSERT #holidays
SELECT id FROM #holiday_201804
RETURN;
END;
GO

SQL trigger with IDENTITY_INSERT

I have two tables: Table1 is all the companies, Table2 is companies whose name start with A.
Table1 company (companyId int, companyName varchar(50), companySize int)
Table2 companyStartWithA (companyId int, companyName varchar(50), companySize int)
What I want to do is to create a trigger so that when I insert/update/delete something in Table1, it will automatically do the same in Table2
My code:
CREATE TRIGGER A_TRG_InsertSyncEmp
ON company
AFTER INSERT
AS
BEGIN
INSERT INTO companyStartWithA
SELECT *
FROM INSERTED
WHERE inserted.companyName LIKE 'A%'
END
And I get an error:
An explicit value for the identity column in table 'companyStartWithA' can only be specified when a column list is used and IDENTITY_INSERT is ON.
What can I do?
Thanks
The problem is the fact that you're not explicitly specifying the column in the INSERT statement, and using a SELECT * to fill the data. Both are big no-no's - you should always explicitly specify the column that you want to insert into, and you should always explicitly specify the columns that you want to select. Doing so will fix this problem:
CREATE TRIGGER A_TRG_InsertSyncEmp
ON company
AFTER INSERT
AS
BEGIN
INSERT INTO companyStartWithA (companyName, companySize)
SELECT companyName, companySize
FROM INSERTED
WHERE inserted.companyName LIKE 'A%'
END
But as Sean Lange absolutely correctly commented - this should really be just a view rather than a separate table.....
CREATE VIEW dbo.CompanyStartsWithA
AS
SELECT companyId, companyName, companySize
FROM dbo.Company
WHERE Name LIKE 'A%'
and then you don't need any messy triggers or anything - just insert into dbo.Company and all companies with a name that starts with an A will be visible in this view....

SELECT INTO a table variable in T-SQL

Got a complex SELECT query, from which I would like to insert all rows into a table variable, but T-SQL doesn't allow it.
Along the same lines, you cannot use a table variable with SELECT INTO or INSERT EXEC queries.
http://odetocode.com/Articles/365.aspx
Short example:
declare #userData TABLE(
name varchar(30) NOT NULL,
oldlocation varchar(30) NOT NULL
)
SELECT name, location
INTO #userData
FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30
The data in the table variable would be later used to insert/update it back into different tables (mostly copy of the same data with minor updates). The goal of this would be to simply make the script a bit more readable and more easily customisable than doing the SELECT INTO directly into the right tables.
Performance is not an issue, as the rowcount is fairly small and it's only manually run when needed.
...or just tell me if I'm doing it all wrong.
Try something like this:
DECLARE #userData TABLE(
name varchar(30) NOT NULL,
oldlocation varchar(30) NOT NULL
);
INSERT INTO #userData (name, oldlocation)
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;
The purpose of SELECT INTO is (per the docs, my emphasis)
To create a new table from values in another table
But you already have a target table! So what you want is
The INSERT statement adds one or more new rows to a table
You can specify the data values in the
following ways:
...
By using a SELECT subquery to specify
the data values for one or more rows,
such as:
INSERT INTO MyTable
(PriKey, Description)
SELECT ForeignKey, Description
FROM SomeView
And in this syntax, it's allowed for MyTable to be a table variable.
You can also use common table expressions to store temporary datasets. They are more elegant and adhoc friendly:
WITH userData (name, oldlocation)
AS
(
SELECT name, location
FROM myTable INNER JOIN
otherTable ON ...
WHERE age>30
)
SELECT *
FROM userData -- you can also reuse the recordset in subqueries and joins
You could try using temporary tables...if you are not doing it from an application. (It may be ok to run this manually)
SELECT name, location INTO #userData FROM myTable
INNER JOIN otherTable ON ...
WHERE age>30
You skip the effort to declare the table that way...
Helps for adhoc queries...This creates a local temp table which wont be visible to other sessions unless you are in the same session. Maybe a problem if you are running query from an app.
if you require it to running on an app, use variables declared this way :
DECLARE #userData TABLE(
name varchar(30) NOT NULL,
oldlocation varchar(30) NOT NULL
);
INSERT INTO #userData
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;
Edit: as many of you mentioned updated visibility to session from connection. Creating temp tables is not an option for web applications, as sessions can be reused, stick to temp variables in those cases
Try to use INSERT instead of SELECT INTO:
DECLARE #UserData TABLE(
name varchar(30) NOT NULL,
oldlocation varchar(30) NOT NULL
)
INSERT #UserData
SELECT name, oldlocation
First create a temp table :
Step 1:
create table #tblOm_Temp (
Name varchar(100),
Age Int ,
RollNumber bigint
)
**Step 2: ** Insert Some value in Temp table .
insert into #tblom_temp values('Om Pandey',102,1347)
Step 3: Declare a table Variable to hold temp table data.
declare #tblOm_Variable table(
Name Varchar(100),
Age int,
RollNumber bigint
)
Step 4: select value from temp table and insert into table variable.
insert into #tblOm_Variable select * from #tblom_temp
Finally value is inserted from a temp table to Table variable
Step 5: Can Check inserted value in table variable.
select * from #tblOm_Variable
OK, Now with enough effort i am able to insert into #table using the below :
INSERT #TempWithheldTable SELECT
a.SuspendedReason,
a.SuspendedNotes,
a.SuspendedBy ,
a.ReasonCode FROM OPENROWSET( BULK 'C:\DataBases\WithHeld.csv', FORMATFILE =
N'C:\DataBases\Format.txt',
ERRORFILE=N'C:\Temp\MovieLensRatings.txt'
) AS a;
The main thing here is selecting columns to insert .
One reason to use SELECT INTO is that it allows you to use IDENTITY:
SELECT IDENTITY(INT,1,1) AS Id, name
INTO #MyTable
FROM (SELECT name FROM AnotherTable) AS t
This would not work with a table variable, which is too bad...

Resources