Select operations from tables using JOINS in stored procedures - sql-server

I have three sql tables called financetrail , fooperson and idDog .All of them have the column idFoo :
I have created the following stored procedure
CREATE PROCEDURE [dbo].[getCustomerFinance] #idFinanceType INT
AS
BEGIN
SELECT idCustomer
FROM financetrail
where idFinanceType = #idFinanceType ;
END
GO
so i can dynamically choose customers of a certain finance type.
The above procedure generates a table along these lines:
I also have this query
SELECT firstName , lastName
FROM IdDog RIGHT JOIN fooPerson
ON IdDog.idFoo = fooPerson.idFoo WHERE IdDog.idIdDog IS NULL;
The result gives me all customers who don't have a dog in the dog table.
What i want to do ?
I want to create a stored procedure that would give me all the customers who don't have a valid idCard(query above) and are of a certain riskType defined from the stored procedure above .
What i have tried ?
I have tried doing the following :
ALTER PROCEDURE [dbo].[getMissingDogs]
AS
BEGIN
DECLARE #financeFilterTable table ( idCustomer INT)
INSERT INTO #financeFilterTable
EXEC getCustomerRisk 3
SELECT * FROM #financeFilterTable
SELECT firstName , lastName
FROM IdCard RIGHT JOIN FooPerson
ON IdCard.idCustomer = FooPerson.idFoo WHERE IdDog.idIdDog IS NULL;
END
and i get the following results :
In the current result set i have two tables . One table giving Customer ids for customers of a certain risk type and the second table giving the customers who don't have an idCard .
I want to find all customers who fulfill both criteria (have a certain risk type and not have an idCard ) in one table
Is that possible ?

I am not sure if I fully understand your requirement. Would it be possible please to post some sample data and expected query results?
Maybe the stored procecure below works for you?
ALTER PROCEDURE [dbo].[getMissingDogs]
#idFinanceType INT
AS
BEGIN
DECLARE #financeFilterTable table ( idCustomer INT)
INSERT INTO #financeFilterTable
EXEC getCustomerRisk #idFinanceType
SELECT firstName , lastName
FROM IdCard RIGHT JOIN FooPerson ON IdCard.idCustomer = FooPerson.idFoo
INNER JOIN #financeFilterTable AS RiskType ON RiskType.idCustomer = IdCard.idCustomer
WHERE IdDog.idIdDog IS NULL;
END

Related

DBMS stored procedure- get values from existing table

I have a table Age_cal, Vaccine Information and Medical_information table as follows:
I am trying to write a stored procedure where, I will be able to insert the values into a table named vaccine based on the vaccine_information table.
In med_info table we have DOB, and the age is calculated and stored in age_cal table along with the age grp and medicalID (PK). The vaccine information table has name of vaccine and to which age group it needs to be given to.
So while inserting a value into Vaccine table, I want to give the values medicalId, date it was given on , dose no and facility name as parameters. But I want the vaccine name to be automatically selected based on the age group they belong to.
I have written the following stored procedure, but null value is getting inserted into the vaccine_name. Please help me with inserting the vaccine name using the stored procedure.
ALTER PROCEDURE [dbo].[allot_v]
#MedicalID int,
#VaccineDate date,
#DoseNo int,
#facilityName varchar(20)
AS
BEGIN
DECLARE #injectvaccine varchar(20)
SET #injectvaccine = (SELECT dbo.VaccineInformation.VaccineName
FROM dbo.VaccineInformation, dbo.Age_Cal
WHERE dbo.Age_Cal.grp = dbo.VaccineInformation.grp
AND dbo.Age_Cal.MedicalID = #MedicalID)
INSERT INTO [dbo].[Vaccination]
([MedicalID], [VaccineName], [VaccineDate], [DoseNo], [FacilityName])
VALUES (#MedicalID, #injectvaccine, #VaccineDate, #DoseNo, #facilityName)
END
The stored procedure worked with the following code:
ALTER PROCEDURE [dbo].[allot_v]
#MedicalID int,
#VaccineDate date,
#DoseNo int,
#facilityName varchar(20)
AS
BEGIN
DECLARE #injectvaccine varchar(20)
SET #injectvaccine = (SELECT dbo.VaccineInformation.VaccineName
FROM dbo.VaccineInformation, dbo.Age_Cal
WHERE dbo.Age_Cal.grp = dbo.VaccineInformation.grp
AND dbo.Age_Cal.MedicalID = #MedicalID)
-- Insert statements for procedure here
INSERT INTO [dbo].[Vaccination]
([MedicalID], [VaccineName], [VaccineDate], [DoseNo], [FacilityName])
VALUES (#MedicalID, #injectvaccine, #VaccineDate, #DoseNo, #facilityName)
END

PL SQL "Array Type" To TSQL translation

This is my initial PL/SQL code :
TYPE VarcharArray IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;
and i use it in the following code :
PROCEDURE Create(inFatherId IN VARCHAR2, inBarcode IN VarcharArray, inItemId IN VarcharArray)
IS
myCount NUMBER(38);
sampleId_FromDb NUMBER(38);
itemId_FromDb NUMBER(38);
BEGIN
myCount := inBarcode.COUNT;
FOR i IN 1..myCount
LOOP
SELECT ITEM.Id INTO itemId_FromDb FROM ITEM WHERE FatherId = inFatherId AND CampaignItemId = inItemId(i);
SELECT SAMPLE_SEQUENCE.NEXTVAL INTO sampleId_FromDb FROM DUAL;
INSERT INTO CAMPAIGN_SAMPLES(Id, Barcode, ItemId) VALUES(sampleId_FromDb, inBarcode(i), itemId_FromDb);
END LOOP;
END;
I've seen that the array type can be translated into MS SQL with Table-Valued Parameters, however how can i iterate in a similar fashion so that i include in the iteration the thee operations ?
In the current PL/SQL implementation i send up to 50.000 elements in the array and the performance is decent. I would desire something similar also in MS SQL.
There's no need to be looping and inserting one row at a time. That's just a way to make your code slower. Since tables don't have any order in them, you need to add one column to define the order. Your type would be like this:
CREATE TYPE VarcharArray AS TABLE(ID int, Item VARCHAR(100));
Then, you can rewrite your procedure as a single INSERT statement.
CREATE PROCEDURE SomeProcedure(
#FatherId AS VARCHAR, --This might need a length or will be defaulted to length 1
#Barcode AS VarcharArray READONLY,
#ItemId AS VarcharArray READONLY
)
AS
INSERT INTO CAMPAIGN_SAMPLES(Id, Barcode, ItemId)
SELECT NEXT VALUE FOR SAMPLE_SEQUENCE,
bc.Item,
i.Id
FROM ITEM i
JOIN #ItemId ii ON i.CampaignItemId = ii.Item
JOIN #Barcode bc ON ii.ID = bc.ID
WHERE i.FatherId = #FatherId;
You could also create a table with both values and prevent any ordering problems that could occur.
CREATE TYPE BarcodeItems AS TABLE(Item VARCHAR(100), Barcode VARCHAR(100));
GO
CREATE PROCEDURE SomeProcedure(
#FatherId AS VARCHAR, --This might need a length or will be defaulted to length 1
#BarcodeItems AS BarcodeItems READONLY
)
AS
INSERT INTO CAMPAIGN_SAMPLES(Id, Barcode, ItemId)
SELECT NEXT VALUE FOR SAMPLE_SEQUENCE,
bi.Item,
i.Id
FROM ITEM i
JOIN #BarcodeItems bi ON i.CampaignItemId = bi.Item
WHERE i.FatherId = #FatherId;

msforeachdb with multiple queries into a single result set creating a temp table

I am trying to run a report to get some metrics about our users and the different applications we have. Each of our customers have a different database so I need to run the same queries across several databases. The query I use works like a charm but then I need to manually copy and paste each of the results to make everything readable. So I thought I would create a temp table, then insert each query result into a different column in the table to also avoid duplicate code but somehow, most of the results returned are null or show numbers that do not much when running the query without using the temp table. Any ideas as to what I am might be doing wrong? Can't seem to figure it out
DROP TABLE #ReportAlexis
CREATE TABLE #ReportAlexis
(
CompanyName VARCHAR(MAX),
TotalUsers INT,
UsersSinceDate INT,
TotalAppUsers INT,
AppUsersSinceDate INT,
Number_of_Logins_SinceDate INT,
);
EXEC master.dbo.sp_msforeachdb 'if ''?'' in (''master'',''model'',''msdb'',''tempdb'') return
declare #startdate DATETIME = ''2019-01-01''
INSERT INTO #ReportAlexis(Companyname) Select companyname from CompanyTable where Databasename = ?;
USE ?;
INSERT INTO #ReportAlexis(TotalUsers) Select count (*) as TotalUsers from User;
INSERT INTO #ReportAlexis(UsersSinceDate) Select count (*) as UsersSinceDate from User where CreatedDate >= #startdate;
INSERT INTO #ReportAlexis(TotalAppUsers) Select count (*) as TotalAppUsers from Users where UserTypeID = 5;
INSERT INTO #ReportAlexis(AppUsersSinceDate) Select count (*) as AppUsersSinceDate from Users where UserTypeID = 5 and CreatedDate >= #startdate;
INSERT INTO #ReportAlexis(Number_of_Logins_SinceDate) Select count (*) as Number_of_Logins_SinceDate from UserLoginDetails where UserID in (Select UserID from Users where UserTypeID = 5) and LoginTime >= #startdate
'
SELECT * FROM #ReportAlexis
I assume the scope is disconnected, try a ##table (global temp table). the #table is only easily accessible within scope though the real name can be found in:
select t.name from tempdb.sys.tables t where t.name like '#ReportAlexis%'
/* it's still better to use a global temp table */
CREATE TABLE ##ReportAlexis
(
CompanyName VARCHAR(MAX),
TotalUsers INT,
UsersSinceDate INT,
TotalAppUsers INT,
AppUsersSinceDate INT,
Number_of_Logins_SinceDate INT,
);

T-SQL Check if list has values, select and Insert into Table

I'm quite new to T-SQL and currently struggling with an insert statement in my stored procedure: I use as a parameter in the stored procedure a list of ids of type INT.
If the list is NOT empty, I want to store the ids into the table Delivery.
To pass the list of ids, i use a table type:
CREATE TYPE tIdList AS TABLE
(
ID INT NULL
);
GO
Maybe you know a better way to pass a list of ids into a stored procedure?
However, my procedure looks as follows:
-- parameter
#DeliveryModelIds tIdList READONLY
...
DECLARE #StoreId INT = 1;
-- Delivery
IF EXISTS (SELECT * FROM #DeliveryModelIds)
INSERT [MyDB].[Delivery] ([DeliveryModelId], [StoreId])
OUTPUT inserted.DeliveryId
SELECT ID FROM #DeliveryModelIds;
If the list has values, I want to store the values into the DB as well as the StoreId which is always 1.
If I insert the DeliveryIds 3,7,5 The result in table Delivery should look like this:
DeliveryId | StoreId | DeliveryModelId
1...............| 1...........| 3
2...............| 1...........| 7
3...............| 1...........| 5
Do you have an idea on how to solve this issue?
THANKS !
You can add #StoreId to your select for your insert.
...
IF EXISTS (SELECT * FROM #DeliveryModelIds)
INSERT [MyDB].[Delivery] ([DeliveryModelId], [StoreId])
OUTPUT inserted.DeliveryId
SELECT ID, #StoreId FROM #DeliveryModelIds;
Additionally, if you only want to insert DeliveryModelId that do not currently exist in the target table, you can use not exists() in the where clause like so:
...
IF EXISTS (SELECT * FROM #DeliveryModelIds)
INSERT [MyDB].[Delivery] ([DeliveryModelId], [StoreId])
OUTPUT inserted.DeliveryId
SELECT dmi.ID, #StoreId
FROM #DeliveryModelIds dmi
where not exists (
select 1
from MyDb.Delivery i
where i.StoreId = #StoreId
and i.DeliveryModeId = dmi.ID
);
You need to modify the INSERT statement to:
INSERT [MyDB].[Delivery] ([DeliveryModelId], [StoreId])
OUTPUT inserted.DeliveryId
SELECT ID, 1 FROM #DeliveryModelIds;
So you are also selecting a literal, 1, along with ID field.

How to use stored procedure with table-valued parameters to compare two input tables

I am trying to write a stored procedure to compute the differences between two input tables.
Stored procedure is used to calculate differences between two tables (both tables have the same predefined table structure), the stored procedure will provide records added, removed or updated when comparing table 1 to table 2.
Example:
table 1 New has 3 records: A, B and C
table 2 has 3 records: B', C and D
B' denotes a change to one or multiple fields within the record B
The output of this stored procedure call will be
A-addition
B-update
D-Removal
I have written a query to compute the difference between two tables, but finding it hard to translate to stored procedure.
Table structure:
X varchar (10)
Y int
Z datetime
SELECT
table1.*, ChangeType = 'Addition'
FROM
table1
WHERE
NOT EXISTS (SELECT *
FROM table2
WHERE table1.x = table2.x)
UNION ALL
SELECT
table2.*, ChangeType = 'Removal'
FROM
table2
WHERE
NOT EXISTS (SELECT *
FROM table1
WHERE table1.x = table2.x)
UNION ALL
SELECT
table1, ChangeType = 'Update'
FROM
table2
INNER JOIN
table1 ON table1.x = table2.x
WHERE
table1.Y <> table2.Y OR table1.Z <> table2.Z
Please also include the stored procedure execution script as well.
I think you are looking for the MERGE sentence. You can put table1 as target and table2 as source based on certain values and decide what to do in case the match or not: https://msdn.microsoft.com/en-us/library/bb510625.aspx
In your case it would be something like:
MERGE table1 AS target
USING table2 AS source (x, y, z)
ON (target.x= source.x)
WHEN MATCHED
--do something
WHEN NOT MATCHED BY TARGET
--do something different
WHEN NOT MATCHED BY SOURCE
--something else
As to how to receive a table as a parameter in a SP, you need to follow the next steps:
Create a DATA TYPE
CREATE TYPE tableExample (X varchar (10),
Y int,
Z datetime)
Pass it to the SP:
CREATE PROC sp_mysp #table1 tableExample, #table2 tableExample
AS ...
I prefer a single pass, using a case statement to classify the action.
CREATE PROCEDURE CompareTables
AS
BEGIN
SELECT ChangeType = CASE
WHEN table2.x IS NULL THEN
'Addition'
WHEN table1.x IS NULL THEN
'Removal'
WHEN table1.Y <> table2.Y
OR table1.Z <> table2.Z THEN
'Update'
ELSE
'No Change'
END,
table1.*,
table2.*
FROM table2
FULL OUTER JOIN table1
ON table1.x = table2.x
WHERE table2.x IS NULL
OR table1.x IS NULL
OR NOT ( table1.Y = table2.Y
AND table1.Z = table2.Z
);
END;

Resources