Setting variable SQL Procedure - sql-server

I am working on a database that contains customers, products, timesheets, etc for a store. The question I am working on involves creating a procedure that will change an "on/off" column to off (the product is available (1) by default, and this procedure turns it to 0) I have writen the procedure fine:
create proc p_fudgemart_deactivate_product
(
#product_id int
)
as
begin
update fudgemart_products
set product_is_active = 0
where product_id = #product_id
end
but the issue then comes when we are given a product NAME, and need to write a select statement to change that product to unavailable. I know that this requires the use of a variable, but I cannot figure out how to set the variable to the product id of that product. I was thinking something along the lines of:
Declare #prod_name_id int
set #prod_name_id= (select product_id from fudgemart_products
where product_name = 'Slot Screwdriver')
execute p_fudgemart_deactivate_product product_id #prod_name_id
Am I able to use a select in my variable declaration like this?

actually you're on the right track. try something like this:
declare #prod_name_id int
select #prod_name_id = product_id
from fudgemart_products
where product_name = 'Slot Screwdriver'
exec p_fudgemart_deactivate_product
#product_id = #prod_name_id

If you are using SQL Server 2008 or later, you can declare and assign in one statement:
DECLARE #prod_name_id int = ( SELECT product_id
FROM fudgemart_products
WHERE product_name = 'Slot Screwdriver'
);
EXECUTE p_fudgemart_deactivate_product #product_id = #prod_name_id;

Related

How to iterate through column name of a table and pass value to UDF in MSSQL while loop

TableName: Stocks
I am trying to fetch profit or loss of stock company in stocks table.(Refer output table in below screenshot)
I had created User defined function with passing parameter as stock company and return integer value which shows wither profit or loss.
CREATE FUNCTION FetchStockProfitLoss(
#stockCompany nvarchar(50)
)
RETURNS INT
AS
BEGIN
declare #buyStock as INT;
declare #sellStock as INT;
declare #profitLoss as INT;
Set #buyStock = (SELECT SUM(stockvalue) from stocks where stockcompany=#stockCompanyand transactiontype='buy');
Set #sellStock = (SELECT SUM(stockvalue) from stocks where stockcompany=#stockCompanyand transactiontype='sell');
set #profitLoss = (#buyStock) -(#sellStock);
RETURN #profitLoss
END;
Calling UDF by passing single StockCompany.
SELECT distinct stock_symbol,dbo.FetchIndStock('Google') as ProfitLoss from stocks where stock_symbol='Google'
How do I achieve same result(AS OUTPUT) for all stockcompanies using loop in stored procedure?
Sample Data:
TransactionID is primary column.
Output:
A UDF seems unnecessary here
A simple conditional aggregation should do the trick
Select StockCompany
,ProfitLoss = sum( StockValue * case when TransactionType = 'Buy' then -1 else 1 end)
From YourTable
Group By StockCompany

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

Making a single Transaction for multiple items in SQL SERVER 2012

Help me for my POS. I'm doing a Transaction for fast-food. I'm really confuse on building codes for the transaction. I want to do it like this
ID ! Transaction ID ! Product Name !
ID ! TRANSACTIONID ! PRODUCT
1 TR1 DISH1
2 TR1 DISH2
3 TR2 DISH3
4 TR3 DISH4
5 TR3 DISH5
6 TR3 DISH2
ITS MORE LIKE THAT. Sorry if my code has no clarity please understand me. This is my first time asking. Thanks
The below code is my pattern for inserting it into database but transaction ID won't be like on top.
Private Sub TransactionUpdate()
Dim pn, pp, pq, pt As String
If ListView1.Items.Count = Nothing Then Exit Sub
PanelOrder()
For Each item As ListViewItem In ListView1.Items
pn = item.SubItems(0).Text
pp = item.SubItems(1).Text
pq = item.SubItems(2).Text
pt = item.SubItems(3).Text
SQL.AddParam("#transactionstate", "Served")
SQL.AddParam("#productname", pn)
SQL.AddParam("#employeeid", txtusername.Text.ToUpper)
SQL.AddParam("#employeename", btnlogin.Text)
SQL.AddParam("#productprice", pp)
SQL.AddParam("#productquantity", pq)
SQL.AddParam("#producttotal", pt)
SQL.ExecQuery("Insert Into Emp_Transaction(ProductName,EmployeeName,TotalPrice,Transaction_Date,Transaction_Time,ProductQuantity,TransactionState) " &
"Values(#productname,#employeename,#producttotal,GETDATE(),GETDATE(),#productquantity,#transactionstate)")
'TransactionID,ProductName,EmployeeName,TotalPrice,Transaction_Date,Transaction_Time,ProductQuantity,TransactionState
SQL.ExecQuery("Update Emp_Transaction " &
"Set ProductID=(SELECT Product.ProductID from Product Where Product.ProductName=Emp_Transaction.ProductName), EmployeeID=(SELECT Employees.EmployeeID from Employees Where Employees.Name=Emp_Transaction.EmployeeName)")
Next
If SQL.HasException(True) Then Exit Sub
End Sub
Personally, I would write a stored procedure to do the insert, and then I would call the stored procedure with the same parameters.
The procedure would look like this
CREATE PROCEDURE dbo.AddTransaction #productname VARCHAR(100)
,#employeename VARCHAR(100)
,#producttotal INTEGER
,#productquantity INTEGER
,#transactionstate VARCHAR(100)
AS
BEGIN
DECLARE #ProductId INT, #EmployeeId INT;
SELECT #ProductId = productID FROM dbo.Product WHERE ProductName = #productname;
SELECT #EmployeeId = SELECT EmployeeID FROM dbo.Employees WHERE name = #EmployeeName;
INSERT INTO dbo.Emp_Transaction(ProductName,EmployeeName,TotalPrice,Transaction_Date,Transaction_Time,ProductQuantity,TransactionState
,ProductId, EmployeeId)
VALUES(#productname,#employeename,#producttotal,GETDATE(),GETDATE(),#productquantity,#transactionstate
,#ProductId, #EmployeeID );
END;
Of course, you might have to change the datatypes a bit.
Having said that, there seems to be at least one problem with your Emp_Transaction table in that it is not "normalised".
Having both ProductId and ProductName in the table is not normalised because one is directly derived from the other one.
You should probably remove ProductName
The same goes for EmployeeId and EmployeeName
Another detail is that it is better practice to always specify the schema name of your table, like dbo.Emp_Transaction instead of Emp_Transaction.
You should try the following approach.Try first running your insert statement in the database directly.This will help you to understand if your query is correct or not.Once you do that then you should put the query into your code and then debug the code.

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.

Resources