Query table-per-month data without dynamic SQL - sql-server

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

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);

Multiple values in one parameter in a stored procedure

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

Triggers after insert

I have a table that has the following columns, and I cannot modify the schema (i.e. I can't modify the table or add an identity field).
What I want is to create a trigger to update one column to treat it as an identity field.
accountno firstname lastname keyField
jku45555 John Doe 123
Now what I want is when I insert the next record, I grab the KeyFieldId of the previous record and update the newly inserted record to be 124 (keep in mind this a Varchar field).
I need the best possible way of doing this, and like I said modifying the table is not an option. Thanks!
You want to do something like this... For a table named "Foo", with two columns, First Name and KeyFieldId (both varchar), this trigger will do what you want:
-------------------------------------------------------------------------
-- These lines will create a test table and test data
--DEBUG: CREATE TABLE Foo (FirstName varchar(20), KeyFieldId varchar(10))
--DEBUG: INSERT INTO Foo VALUES ('MyName', '145')
--
CREATE TRIGGER test_Trigger ON Foo
INSTEAD OF INSERT
AS
BEGIN
DECLARE #maxKeyFieldId int;
SELECT #maxKeyFieldId = MAX(CAST(KeyFieldId AS int)) FROM Foo;
WITH RowsToInsert AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY (CAST(KeyFieldId AS int))) AS RowNum
FROM inserted
) INSERT INTO Foo (FirstName, KeyFieldId)
SELECT FirstName, #maxKeyFieldId + RowNum
FROM RowsToInsert;
END
Things to note here:
Create an INSTEAD OF INSERT trigger
Find the "max" value of the INTEGER value of your KeyFieldID
Create a CTE that selects everything from the 'inserted' collection
Add a column to the CTE for a Row Number
Do the actual INSERT by adding row number to the max KeyFieldID

SQL Script add records with identity FK

I am trying to create an SQL script to insert a new row and use that row's identity column as an FK when inserting into another table.
This is what I use for a one-to-one relationship:
INSERT INTO userTable(name) VALUES(N'admin')
INSERT INTO adminsTable(userId,permissions) SELECT userId,255 FROM userTable WHERE name=N'admin'
But now I also have a one-to-many relationship, and I asked myself whether I can use less SELECT queries than this:
INSERT INTO bonusCodeTypes(name) VALUES(N'1500 pages')
INSERT INTO bonusCodeInstances(codeType,codeNo,isRedeemed) SELECT name,N'123456',0 FROM bonusCodeTypes WHERE name=N'1500 pages'
INSERT INTO bonusCodeInstances(codeType,codeNo,isRedeemed) SELECT name,N'012345',0 FROM bonusCodeTypes WHERE name=N'1500 pages'
I could also use sth like this:
INSERT INTO bonusCodeInstances(codeType,codeNo,isRedeemed)
SELECT name,bonusCode,0 FROM bonusCodeTypes JOIN
(SELECT N'123456' AS bonusCode UNION SELECT N'012345' AS bonusCode)
WHERE name=N'1500 pages'
but this is also a very complicated way of inserting all the codes, I don't know whether it is even faster.
So, is there a possibility to use a variable inside SQL statements? Like
var lastinsertID = INSERT INTO bonusCodeTypes(name) OUTPUT inserted.id VALUES(N'300 pages')
INSERT INTO bonusCodeInstances(codeType,codeNo,isRedeemed) VALUES(lastinsertID,N'123456',0)
OUTPUT can only insert into a table. If you're only inserting a single record, it's much more convenient to use SCOPE_IDENTITY(), which holds the value of the most recently inserted identity value. If you need a range of values, one technique is to OUTPUT all the identity values into a temp table or table variable along with the business keys, and join on that -- but provided the table you are inserting into has an index on those keys (and why shouldn't it) this buys you nothing over simply joining the base table in a transaction, other than lots more I/O.
So, in your example:
INSERT INTO bonusCodeTypes(name) VALUES(N'300 pages');
DECLARE #lastInsertID INT = SCOPE_IDENTITY();
INSERT INTO bonusCodeInstances(codeType,codeNo,isRedeemed) VALUES (#lastInsertID, N'123456',0);
SELECT #lastInsertID AS id; -- if you want to return the value to the client, as OUTPUT implies
Instead of VALUES, you can of course join on a table instead, provided you need the same #lastInsertID value everywhere.
As to your original question, yes, you can also assign variables from statements -- but not with OUTPUT. However, SELECT #x = TOP(1) something FROM table is perfectly OK.

Insert into a table several values in a temp table

I have several values in a temp table called #tempIQ and I want to insert into a table called IQGroups using the same Group identifier. Assuming everyone has a unique IQ:
create table #tempIQ
(
id int
)
declare #GroupIDas int
set #GroupID=1001
select iq from #tempIQ
1,2,86,99,101,165,180,201
I want to insert these ids from the temp table into a grouping called IQGroups but am having difficulty finding a simple solution.
-- now try and insert all the iqs for a group into the IQGroups table from the #tempIQ table.
insert into IQGroups (GroupID, IQ) values (#GroupID, #tempiQ.iq)
Try this:
INSERT INTO IQGroups (GroupID, IQ)
SELECT #GroupID, IQ
FROM #tempIQ
Try using the SELECT statement.
INSERT INTO IQGroups (GroupID, IQ)
SELECT #GroupID, iq
FROM #tempIQ
This is the standard way to select multiple rows.
this is another way to do this,
select id, 1001 as GroupID
into IQGroups
from #tempIQ

Resources