Using the count as a parameter in stored procedure? - sql

I'm looking to try creating a stored procedure that will search for duplicate rows based on a certain number (i.e., if I wanna see an instance of 2 identical rows, use "having count(*)>2)
select invoice.first_name, invoice.last_name, invoice.date_ordered,
sum(total_cost) AS Total_Spent
from invoice
group by invoice.last_name
having count(*)>2;
What I would like to create is the option for the person to specify the count whenever they call the procedure so they don't have to go into the procedure, edit the query, save, etc.
Is there a way to turn it into a parameter?

Try like this:
set nocount on;
create proc dbo.test
#nas int
as
begin
select invoice.first_name, invoice.last_name, invoice.date_ordered,
sum(total_cost) AS Total_Spent
from invoice
group by invoice.last_name
having count(*)>#nas;
end
exec dbo.test #nas=2

First of all, what do you mean by:
the option for the person to specify the count
If you mean that you want to specify the number of identical records returned, then you could:
ALTER PROCEDURE YourProcedureName (#Count INT) AS
BEGIN
select invoice.first_name, invoice.last_name, invoice.date_ordered,
sum(total_cost) AS Total_Spent
from invoice
group by invoice.last_name
having count(*)>#Count;
END
This will create an input parameter so that when the user runs the procedure they can specify that the number of identical rows will be greater than the #Count Parameter.
If you want the user to be able to count on a specific column(s), that becomes a bit more tricky.

Related

Stored procedure has multiple SELECT statements

This stored procedure has multiple SELECT statements - I need to write a condition based on one SELECT statement results among them without altering the stored procedure:
CREATE PROC Test
AS
BEGIN
SELECT 1 AS ID
FROM EMPLOYEE
SELECT NAME, ADDRESS, STATE
FROM EMPLOYEE --NEED TO TAKE ROW COUNT
END
After executing the stored procedure, I'll get 2 result sets. But I need to row count of 2nd select statement, without altering the stored procedure.
Based on that rowcount, I need to work further.
exec Test
select ##rowcount
In this case, ##rowcount will always return last result set row count.

Create a stored procedure that keeps returning new rows

I have a table with x number of rows. I want to create a stored procedure that always select a new row and return that row (when all rows has been returned it will start over from first row). My idea is to select top 1 row (ordered by a date time row) return that from the stored procedure and then set an datetime column so next time it will be a new row that is returned. It needs to be thread safe so I would expect some row locking is needed (I don't know if this is true). How would you create a stored procedure like that? I am not sure of you need to use variables or it can be done in a single query. Something like:
select top 1 *
from [dbo].[AppRegistrations]
order by LastUsed
update [dbo].[AppRegistrations]
set LastUsed = getdate()
In the comments it is stated that it cannot be done in a single query. If I added following to a stored procedure will it then be thread safe? Or do I need to add a lock? And does the query make sense or should it be done differently?
declare #id int
declare #name as nvarchar(256)
select top 1 #id=id,#name=name from [dbo].[AppRegistrations] order by LastUsed
Update [dbo].[AppRegistrations] set LastUsed=getdate() where id=#id
select #id,#name
It is important that another query cannot interrupt returning a unique row because it updates a row between the select and the update. That is why I wanted it in a single query.
I tried to gather everything up and added a row lock. Following sample works as expected, but I dont know whether the row lock is the right way, or I should expect some challenges. Can someone validate if this approach is correct?
BEGIN TRAN
declare #id int
declare #name as nvarchar(256)
select top 1 #id=id,#name=name from [dbo].[AppRegistrations] WITH (HOLDLOCK, ROWLOCK) order by LastUsed
Update [dbo].[AppRegistrations] set LastUsed=getdate() where id=#id
select #id as id,#name as name
COMMIT TRAN
I make a good number of assumptions here
UPDATE [dbo].[AppRegistrations]
SET LastSelected = CURRENT_TIMESTAMP
OUTPUT INSERTED.*
WHERE Id = (SELECT TOP (1) Id
FROM [dbo].[AppRegistrations]
ORDER BY LastSelected
)
Here is some background on the OUTPUT https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-ver15
Here is another reference where you can do slightly more complex things https://learn.microsoft.com/en-us/sql/t-sql/queries/update-transact-sql?view=sql-server-ver15#CaptureResults

Get a specific column from a returned result of SP?

I have a stored procedure that returns a result, let's say it return rows of products. But each product status is not in our hand(can't get it). Our DBA just gave us another stored procedure to get the status of a product. We need to get individual product status by calling their SP. Let's say we have Product table,
CREATE TABLE PRODUCTS
(
ID INT,
Name NVARCHAR(100)
)
CREATE PROCEDURE GetProducts
AS
BEGIN
INSERT INTO #TEMPTABLE
SELECT * FROM PRODUCTS; -- Yes Too Much simplified
-- Create cursor and set additional status in #TEMPTABLE
END;
EXEC GetStatus #ProductId; -- SP That need to get status
The problem is that GetStatus is only way to get the status and this sp sometimes return 2 columns, sometimes 4 and sometimes 8. The return columns will always include Status column for sure.
If columns names is fixed then there is no problem. Is there is a way to create dynamic table at the time of executing SP.
Tried this but not working,
WITH DynamicTable AS
(
EXEC GetStatus
)
The answer to your question is no. There is no good way to get the value of a specific column returned by a stored procedure that can return a dynamic set of columns.
I say no "good" way, because of course there's a WAY. You can write an INSERT EXEC statement for every possible set of columns that the procedure can return and wrap each one in a TRY..CATCH block. If the first one errors, try the next one. As soon as you hit one that doesn't error, get the Status from it, and skip the rest.
That's the answer to your question. The solution to your problem, however, is to replace the GetStatus stored procedure with a Table-valued function. Then you can select from it, join to it, etc. I think the function would have to always return a consistent number of columns, but that would be better anyway, and the columns that aren't needed in a specific case could just be left empty or NULL.

Get count of records of a table which return from stored procedure

I have a stored procedure, which is returning a table. I just want the count of the records is it possible
My Procedure
create procedure Test
as begin
select * From Student
end
exec Test
will give the records out put
I want the count
NB: I need the sp to return the results of select statement.In another place I need the count of the records returned by sp and columns in the student table is dynamic.
I am expecting an answer without modifying stored procedure.
You can select the data into a temporary table like below. However, you have to use OPENQUERY to do so. You must also enable data access on your server first.
Exec sp_serveroption 'ServerName', 'data access', 'true'
SELECT * INTO #TempTable
FROM OPENQUERY("ServerName", 'EXEC Test')
SELECT COUNT(*) FROM #TempTable
NB: I need the sp to return the results of select statement.
Use your stored procedure as is. That is,
create procedure Test
as begin
select * From Student
end
In another place I need the count of the records returned by sp and
columns in the student table is dynamic.
If this other place is another SP, then use rowcount. You use it this way :
EXEC [sp_WhateverTheSPNameIs]
select ##rowcount
Read about ##RowCount. This is all you need.

Inserting multiple rows with SQL where a record does not exist

I want to insert multiple rows of data into a MySQL database, but only when my order_id field is unique. This is the current query I have, which doesn't work. Lets say a record with an order_id of 2 is already in the table:
INSERT INTO conversion
(user_id,url_id,order_id,sale,commission,transaction_date,process_date)
VALUES (1,1,1,'32',0.3995,'2010-11-15 12:15:18','2010-11-15 12:15:18'),
(3,6,2,'*not-available*',0.001975,'2010-11-15 12:15:18','2010-11-15 12:15:18')
WHERE (order_id <> 3);
Any help is appreciated.
Tom
Solved by using REPLACE.
Example:
REPLACE INTO conversion (user_id,url_id,order_id,sale,commission,transaction_date,process_date) VALUES (1,1,3,'32',0.3995,'2010-11-15 12:50:31','2010-11-15 12:50:31'),(1,2,2,'*not-available*',0.001975,'2010-11-15 12:50:31','2010-11-15 12:50:31');
url: http://dev.mysql.com/doc/refman/5.0/en/replace.html
Thanks all.
INSERT doesn't support the WHERE clause because if you're inserting it implies that the record doesn't currently exist, so therefore there would be nothing for the WHERE clause to look at.
The way to do it in the example you've given is simply not to call the INSERT statement if the order_id field in your insert doesn't match the criteria you want.
If you're calling INSERT multiple times, you'd have some sort of code (either SQL or an external program) which loops through the rows you're inserting; this would be where you'd filter it.
If I am in a similar situation, I would create a stored procedure to handle the logic of figuring out whether an order_id already exists.
--Run this first
--It will create a stored procedure call InsertConversion
--Begin of stored procedure
CREATE PROCEDURE InsertConversion
#user_id int,
#url_id int,
#order_id int,
#sale varchar(5),
#commission money,
#transaction_date datetime,
#process_date datetime
AS
BEGIN
SET NOCOUNT ON;
if not exists(select order_id from conversion where order_id = #order_id)
begin
INSERT INTO conversion(user_id, url_id, order_id, sale, commission, transaction_date, process_date)
VALUES(#user_id, #url_id, #order_id, #sale, #commission, #transaction_date, #process_date)
end
END
GO
--End of stored procedure
Once the store procedure created, you can execute it and pass in the same values as you would pass into an INSERT/VALUES statement:
exec InsertConversion 1,1,1,'32',0.3995,'2010-11-15 12:15:18','2010-11-15 12:15:18'
exec InsertConversion 3,6,2,'*not-available*',0.001975,'2010-11-15 12:15:18','2010-11-15 12:15:18'
If you want to be fancy, you can include a couple of 'print' statement in the store procedure to tell you whether it inserts the record.