getting one random row from a table inside a function- sql server - sql-server

i have this procedure in sql.
the requirment is:
if condition (for example i put 1=1 ..) then [run another procedure or function that will random from table with values one value and return it.] else 1
for example:
case when 1=1 then (dbo.myFunc #input) else 1
this is myTable: '1','2','3'
and i want this function to random from it one value
CREATE FUNCTION dbo.myFunc (#input int)
RETURNS int
AS BEGIN
declare #rndValue int
set #rndValue = (SELECT top 1 * FROM myTable ORDER BY newID())
RETURN #rndValue
END
the problem is that in function i cannot run newID(), and if i want to use procedure instead of function i cannot run it from case statement.
what are u suggest.? thanks alot.

I think you need a code like this:
set x = case when 1=1 then (select top(1) val from myTable order by newid()) else 1 end;
SQL Fiddle

Related

Stored procedure only executes correctly on first execution

I've written this SQL Server stored procedure that inserts records into another table based on the order frequency of customers in another table. It assigns a rank to each customer based on their order frequency. When I create the procedure and execute it for the first time, it works fine and inserts the correct records into the table. But when I clear the table and try to execute the procedure again, no records are added. I have to delete the procedure, restart SSMS, and create the procedure again for it to work correctly again.
Here is the procedure:
create procedure TopKCustomer (#CustRank decimal(11,0))
as
declare CustCursor cursor local for
select o.CustomerID,c.CustomerName,c.CustomerPostalCode,
count(o.CustomerID) as 'Order Frequency'
from (Customer_T c join Order_T o on c.CustomerID=o.CustomerID)
group by o.CustomerID,c.CustomerName,c.CustomerPostalCode
order by [Order Frequency] desc;
declare #PrevOrderFreq float;
declare #CurrOrderFreq float;
declare #CurrRank decimal(11,0);
declare #CurrCustID decimal(11,0);
declare #CurrCustName varchar(25);
declare #CurrCustPostCode varchar(10);
begin
set #PrevOrderFreq = 0;
set #CurrOrderFreq = 0;
set #CurrRank = 0;
set #CurrCustID = 0;
set #CurrCustName = '';
set #CurrCustPostCode = '';
open CustCursor;
while ##FETCH_STATUS = 0
begin
fetch next from CustCursor into #CurrCustID, #CurrCustName, #CurrCustPostCode, #CurrOrderFreq;
if #CurrOrderFreq <> #PrevOrderFreq
begin
set #CurrRank = (#CurrRank + 1);
if #CurrRank > #CustRank
begin
break;
end
end
insert into TopKCustomer_T
values (#CurrCustID, #CurrCustName, #CurrCustPostCode, #CurrRank, getdate());
set #PrevOrderFreq = #CurrOrderFreq;
end
close CustCursor;
deallocate CustCursor;
end
Here are the tables I'm working with:
Customer_T (CustomerID, CustomerName, CustomerAddress, CustomerCity, CustomerState, CustomerPostalCode)
Order_T (OrderID, CustomerID, OrderDate)
TopKCustomer (CustomerID, CustomerName, CustomerPostalCode, CRank, RankGenerateDate)
I think the problem is
while ##FETCH_STATUS = 0
This will be result of the previous fetch (in other words the fetch from the previous execution of your stored procedure, not what you want).
The usual way I wrote cursor loops is
while 1 =1
begin
fetch next from c into ...
if ##fetch_status != 0 break
...
end
There's no sample data or table structure so I don't know what your data looks like. Below is what I think you want. The inner query count the order per customer. The outer query rank them.
SELECT *
, DENSE_RANK() OVER(PARTITION BY CustomerID ORDER BY OrderFrequency) AS Rnk
FROM (
SELECT *
, COUNT(*) OVER (PARTITION BY o.CustomerID) AS OrderFrequency
FROM Customer_T c
JOIN Order_T o ON c.CustomerID = o.CustomerID
) a

How to sum random rows column in where clause SQL

I have a stored procedure that selects a number of random rows from a table based on a parameter and I need to run this in a loop so it constantly selects random rows until the sum of them is accepted
So far I haven't started the loop yet because I can't figure out how do i use sum of a column as a condition
GO
IF OBJECT_ID('dbo.spx_SELECT_RandomLocalizacoes') IS NOT NULL
DROP PROCEDURE spx_SELECT_RandomLocalizacoes
GO
CREATE PROCEDURE spx_SELECT_RandomLocalizacoes
#Localizacoes_Max int,
#Filtro int,
#Armazem int
AS
BEGIN
SET NOCOUNT ON
SELECT TOP (#Localizacoes_Max) * FROM xInventario
WHERE Armazem = #Armazem AND SUM(Quantidade) > #Filtro
ORDER BY newid()
END
The final result should be a procedure that returns me the rows that obey the condition
EDIT:
I forgot to add that, I have to return the select statement with the random rows with the same seed so i can only do that query once
you can treat your query as a sub-query and SUM it, then apply whatever logic you are looking for
if (SELECT SUM(Randoms.YourField) FROM (SELECT TOP (#Localizacoes_Max) * FROM xInventario
WHERE Armazem = #Armazem AND SUM(Quantidade) > #Filtro
ORDER BY newid()) AS Randoms) = #Target
BEGIN
--do stuff
END

T-SQL different result between code in stored and same code in query pane

I'm working on a procedure that should return a o or a 1, depending on result from parameter calculation (parameters used to interrogate 2 tables in a database).
When I excute that code in a query pane, it gives me the results i'm expecting.
code looks like:
SELECT TOP 1 state, updDate INTO #history
FROM [xxx].[dbo].[ImportHystory] WHERE (db = 'EB') ORDER BY addDate DESC;
IF (SELECT state FROM #history) = 'O'
BEGIN
SELECT TOP 1 * INTO #process_status
FROM yyy.dbo.process_status WHERE KeyName = 'eb-importer';
IF(SELECT s.EndDate FROM #process_status s) IS NOT NULL
IF (SELECT s.EndDate FROM #process_status s) > (SELECT h.updDate FROM #history h)
BEGIN
IF (SELECT MessageLog from #process_status) IS NOT NULL SELECT 1;
ELSE SELECT 0;
END
ELSE
SELECT 1;
ELSE
SELECT 1;
END
ELSE
SELECT 0
I'm in the situation where EndDate from #process_status is null, so the execution returns 1.
Once i put the SAME code in a SP, and pass 'EB' and 'eb-importer' as parameters, it returns 0.
And I exec the procedure with the data from the table right in front of me, so i know for sure that result is wrong.
Inside the procedure:
ALTER PROCEDURE [dbo].[can_start_import] (#keyName varchar, #db varchar, #result bit output)
DECLARE #result bit;
and replace every
SELECT {0|1}
with
SELECT #result = {0|1}
Executed from the Query pane:
DECLARE #result bit;
EXEC [dbo].[can_start_import] #KeyName = 'eb-importer', #db = 'EB', #result = #result OUTPUT
SELECT #result AS N'#result'
Why does this happen?
You are doing a top(1) query without an order by. That means SQL Server can pick any row from table1 that matches the where clause.
If you want to guarantee that the result is the same every time you execute that code you need an order by statement that unambiguously orders the rows.
So, apparently 2 things needed to be done:
set the length of the varchar parameter with a higher length,
filter with ' like ' instead of ' = ' for god knows what reason
Now it work as i expected to do, but i still don't get the different results between the query pane and the procedure if i use the equal...

Only one expression can be specified in the select list when the subquery is not introduced with EXISTS error

i am trying to create sql server procedure with if statement.
i am new to the ms sql server however i tried with the following statements but it gave me the below error Msg 116, Level 16, State 1, Procedure te, Line 9
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
here is the code i wrote
CREATE PROCEDURE test as
BEGIN
SET NOCOUNT ON;
if (select COUNT(load),load,contractor_id from [test].[dbo].[cont]
group by load,contractor_id
having load = (select MIN(load)from [test].[dbo].[cont])
) > 1
begin
SELECT top 1 COUNT(*),load ,contractor_id,name
FROM [test].[dbo].[cont]
group by load,contractor_id,name
having load = (select MIN(load)from [test].[dbo].[cont])
ORDER BY NEWID()
end
ELSE
BEGIN
SELECT top 1 COUNT(*),load ,contractor_id,name
FROM [test].[dbo].[cont]
group by load,contractor_id,name
having load = (select MIN(load)from [test].[dbo].[cont])
END
END
GO
can anyone help please
As the error says you cannot have multiple column selected when you use IF condition. In your first IF condition you are selecting multiple columns, however if conditions requires to have a query that can lead to one value. Other option is you have to use IF EXISTS, that can check count >1 as below
IF (SELECT COUNT(load),load,contractor_id
FROM [test].[dbo].[cont]
GROUP BY load,contractor_id
HAVING load = (SELECT MIN(load)
FROM [test].[dbo].[cont])
AND COUNT(load) >1)
Another thing what I noticed is you are excecuting the query which calculates the min of load multiple times. You can avoid that by storing it in a variable and use it further.
I have modified the procedure as below. Check if this works or not.
CREATE PROCEDURE test as
BEGIN
SET NOCOUNT ON;
DECLARE #count INT
DECLARE #minload INT
SELECT #minload = MIN(load)from [test].[dbo].[cont]
SELECT #count = COUNT(load) from [test].[dbo].[cont]
GROUP BY load,contractor_id
HAVING load = #minload
IF (#count) > 1
BEGIN
SELECT top 1 COUNT(*),load ,contractor_id,name
FROM [test].[dbo].[cont]
WHERE load = #minload
GROUP BY load,contractor_id,name
ORDER BY NEWID()
END
ELSE
BEGIN
SELECT top 1 COUNT(*),load ,contractor_id,name
FROM [test].[dbo].[cont]
GROUP BY load,contractor_id,name
HAVING load = #minload
END
END
UPDATE
Based on your comments, I suppose you can get the result with one simple query as below.
;WITH minLoad(load)
AS
(
SELECT MIN(load)
FROM [test].[dbo].[cont]
)
SELECT TOP 1 COUNT(*),c.load ,c.contractor_id,c.name
FROM [test].[dbo].[cont] c, minLoad
WHERE c.load = minLoad.load
ORDER BY NEWID();

sql server-conditional where clause

Suggest me the proper syntex for below raw condition.
ALTER PROCEDURE [dbo].[pro_name]
#number as int ,
Select * from table
if(#number=0)
begin
set #number=select max(number)from table
end
where table.number=#number
here i need to set #number with max value if input value passed is '0'. and also want to use th e same in wherer clause.
ALTER PROCEDURE [dbo].[pro_name]
#number as int=0 --I recommend a default value here too
as
set #number=case #number when 0 then (select max(number)from [table]) else #number end;
Select * from [table] t
where t.number=#number;
go
EDIT:
Since there is not point in having two exactly the same answers and I was beaten, here is an alternate solution:
alter procedure [dbo].[pro_name]
#number as int as
select top 1 * from [table]
where number = #number or #number = 0
order by [table].number desc
However this will only work if the number column is unique, which may or may not be the case in your case.

Resources