SET Command Appears to be Ignored in MySQL Procedure - mysql

I finally got this function to work correctly until I tried to implement in a production state. When I run this procedure and call, I am only getting a value for the LowerLimit output and a NULL for the UpperLimit output. I added a SELECT in the procedure that shows the results for both the internal variables #lowlim and #upplim are being computed, but it appears that only the set for the LowerLimit variable is working. I've been banging on this for hours and can't figure it out so far. Can anyone see anything obvious I'm missing here?
Here is where the problem is occurring:
SET LowerLimit = #lowlim;
SET UpperLimit = #upplim;
SELECT #lowlim, #upplim;
Here is the full procedure.
DELIMITER $$
DROP PROCEDURE if exists p_GetOutlierLimits;
CREATE DEFINER=`user`#`%` PROCEDURE p_GetOutlierLimits(
IN KPI VARCHAR(255), TableName VARCHAR(100),
OUT LowerLimit decimal(16,6), UpperLimit decimal(16,6)
)
BEGIN
SET #lowlim = 0;
SET #upplim = 0;
SET #SQLExec = CONCAT("
with orderedList AS (
SELECT
",KPI,",
ROW_NUMBER() OVER (ORDER BY ",KPI,") AS row_n
FROM ",TableName,"
),
quartile_breaks AS (
SELECT
",KPI,",
(
SELECT ",KPI," AS quartile_break
FROM orderedList
WHERE row_n = FLOOR((SELECT COUNT(*) FROM ",TableName,")*0.75)
) AS q_three_lower,
(
SELECT ",KPI," AS quartile_break
FROM orderedList
WHERE row_n = FLOOR((SELECT COUNT(*) FROM ",TableName,")*0.75) + 1
) AS q_three_upper,
(
SELECT ",KPI," AS quartile_break
FROM orderedList
WHERE row_n = FLOOR((SELECT COUNT(*) FROM ",TableName,")*0.25)
) AS q_one_lower,
(
SELECT ",KPI," AS quartile_break
FROM orderedList
WHERE row_n = FLOOR((SELECT COUNT(*) FROM ",TableName,")*0.25) + 1
) AS q_one_upper
FROM orderedList
),
iqr AS (
SELECT
",KPI,",
(
(SELECT MAX(q_three_lower)
FROM quartile_breaks) +
(SELECT MAX(q_three_upper)
FROM quartile_breaks)
)/2 AS q_three,
(
(SELECT MAX(q_one_lower)
FROM quartile_breaks) +
(SELECT MAX(q_one_upper)
FROM quartile_breaks)
)/2 AS q_one,
1.5 * ((
(SELECT MAX(q_three_lower)
FROM quartile_breaks) +
(SELECT MAX(q_three_upper)
FROM quartile_breaks)
)/2 - (
(SELECT MAX(q_one_lower)
FROM quartile_breaks) +
(SELECT MAX(q_one_upper)
FROM quartile_breaks)
)/2) AS outlier_range
FROM quartile_breaks
)
SELECT MAX(q_one) OVER () - MAX(outlier_range) OVER () AS lower_limit,
MAX(q_three) OVER () + MAX(outlier_range) OVER () AS upper_limit
INTO #lowlim, #upplim
FROM iqr
LIMIT 1;");
PREPARE stmt FROM #SQLExec;
EXECUTE stmt;
SET LowerLimit = #lowlim;
SET UpperLimit = #upplim;
SELECT #lowlim, #upplim;
END$$
DELIMITER ;
CALL p_GetOutlierLimits('576_VMC_Sol_Savings_Pct','vmctco',#LowerLimit, #UpperLimit);
SELECT #LowerLimit, #UpperLimit;

You need to declare OUT for each parameter:
CREATE DEFINER=`user`#`%` PROCEDURE p_GetOutlierLimits(
IN KPI VARCHAR(255), TableName VARCHAR(100),
OUT LowerLimit decimal(16,6), OUT UpperLimit decimal(16,6)
)
https://dev.mysql.com/doc/refman/8.0/en/create-procedure.html says:
Each parameter is an IN parameter by default. To specify otherwise for a parameter, use the keyword OUT or INOUT before the parameter name.

Related

What is wrong in this mysql function ?

when i run this function
CREATE PROCEDURE alege()
BEGIN
declare v_prenumeNou VARCHAR(15);
declare v_numeRandom INTEGER(10);
declare v_prenumeRandom INTEGER(10);
declare v_idCutremurRandom INTEGER(10);
set v_numeRandom = 1 + CEIL ( RAND() * 50 );
set v_prenumeRandom = 1 + CEIL ( RAND() * 50 );
set v_idCutremurRandom = 1 + CEIL ( RAND() * 50 );
select prenume into v_prenumeNou from (SELECT prenume, rownum as v_rn from voluntari) where v_rn=v_prenumeRandom;
select nume into v_numeNou from (SELECT nume, rownum as v_rn from voluntari) where v_rn=v_numeRandom;
v_idPersoanaNou := v_idPersoanaNou + 1;
INSERT INTO voluntari (IDCUTREMUR, IDPERSOANA, NUME, PRENUME)
VALUES (CONCAT('C',IFNULL(v_idCutremurRandom, '')), CONCAT('V',IFNULL(v_idPersoanaNou, '')) , v_numeNou, v_prenumeNou);
END;
i have this error
[Err] 1248 - Every derived table must have its own alias
how can i solve this ?
You must add an alias to each subquery in your select into statements:
select prenume
into v_prenumeNou
from (SELECT prenume, rownum as v_rn
from voluntari) t1 <-----------
where v_rn=v_prenumeRandom;
select nume
into v_numeNou
from (SELECT nume, rownum as v_rn
from voluntari) t1 <------------
where v_rn=v_numeRandom;
Try with this, just changed the alias of the from clauses (every deribed table must have an alias):
CREATE PROCEDURE alege()
BEGIN
declare v_prenumeNou VARCHAR(15);
declare v_numeRandom INTEGER(10);
declare v_prenumeRandom INTEGER(10);
declare v_idCutremurRandom INTEGER(10);
set v_numeRandom = 1 + CEIL ( RAND() * 50 );
set v_prenumeRandom = 1 + CEIL ( RAND() * 50 );
set v_idCutremurRandom = 1 + CEIL ( RAND() * 50 );
select prenume into v_prenumeNou from (SELECT prenume, rownum as v_rn from voluntari) AS A where v_rn=v_prenumeRandom;
select nume into v_numeNou from (SELECT nume, rownum as v_rn from voluntari) AS B where v_rn=v_numeRandom;
v_idPersoanaNou := v_idPersoanaNou + 1;
INSERT INTO voluntari (IDCUTREMUR, IDPERSOANA, NUME, PRENUME)
VALUES (CONCAT('C',IFNULL(v_idCutremurRandom, '')), CONCAT('V',IFNULL(v_idPersoanaNou, '')) , v_numeNou, v_prenumeNou);
END;

Store values in different variables in SQL, separated by (Comma) ","

I need to separate values and store them in different variables in SQL,
for example
a='3100,3101,3102,....'
And the output should be
x=3100
y=3101
z=3102
.
.
.
create function [dbo].[udf_splitstring] (#tokens varchar(max),
#delimiter varchar(5))
returns #split table (
token varchar(200) not null )
as
begin
declare #list xml
select #list = cast('<a>'
+ replace(#tokens, #delimiter, '</a><a>')
+ '</a>' as xml)
insert into #split
(token)
select ltrim(t.value('.', 'varchar(200)')) as data
from #list.nodes('/a') as x(t)
return
end
GO
declare #cad varchar(100)='3100,3101,3102'
select *,ROW_NUMBER() over (order by token ) as rn from udf_splitstring(#cad,',')
token rn
3100 1
3101 2
3102 3
The results of the Parse TVF can easily be incorporated into a JOIN, or an IN
Declare #a varchar(max)='3100,3101,3102'
Select * from [dbo].[udf-Str-Parse](#a,',')
Returns
RetSeq RetVal
1 3100
2 3101
3 3102
The UDF if needed (much faster than recursive, loops, and xml)
CREATE FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#Delimiter varchar(25))
Returns Table
As
Return (
with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (IsNull(DataLength(#String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A ),
cte3(N) As (Select 1 Union All Select t.N+DataLength(#Delimiter) From cte2 t Where Substring(#String,t.N,DataLength(#Delimiter)) = #Delimiter),
cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(#Delimiter,#String,s.N),0)-S.N,8000) From cte3 S)
Select RetSeq = Row_Number() over (Order By A.N)
,RetVal = LTrim(RTrim(Substring(#String, A.N, A.L)))
From cte4 A
);
--Orginal Source http://www.sqlservercentral.com/articles/Tally+Table/72993/
--Much faster than str-Parse, but limited to 8K
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')
I suggest you to use following query, it's much faster than other functions like cross apply and udf.
SELECT
Variables
,S_DATA
FROM (
SELECT
Variables
,CASE WHEN LEN(LIST2)>0 THEN LTRIM(RTRIM(SUBSTRING(LIST2, NUMBER+1, CHARINDEX(',', LIST2, NUMBER+1)-NUMBER - 1)))
ELSE NULL
END AS S_DATA
,NUMBER
FROM(
SELECT Variables
,','+COMMA_SEPARETED_COLUMN+',' LIST2
FROM Tb1
)DT
LEFT OUTER JOIN TB N ON (N.NUMBER < LEN(DT.LIST2)) OR (N.NUMBER=1 AND DT.LIST2 IS NULL)
WHERE SUBSTRING(LIST2, NUMBER, 1) = ',' OR LIST2 IS NULL
) DT2
WHERE S_DATA<>''
and also you should create a table 'NUMBER' before running the above query.
CREATE TABLE TB (Number INT)
DECLARE #I INT=0
WHILE #I<1000
BEGIN
INSERT INTO TB VALUES (#I)
SET #I=#I+1
END

SQL loop insert using declared table

I have a declared table which has a lot of data in it... I get the data by doing a select query on my InventoryLogs.. now, what I want is to insert this data on another table called MonthlySalesHistoryDetail... However I don't know how to get the values of my declared table...
this is a stored procedure:
Alter Procedure InsertMonthlySalesHistoryEndDate
#CurrentDate date,
#CreatedByID int,
#LastInsertID int
as
Declare #details table
(
RowID int identity(1,1) primary key,
MonthlySalesHistoryID int,
ItemID int,
MeasurementUnitID int,
QuantitySold numeric(18,4),
QuantityReturned numeric(18,4),
TotalSoldAmount numeric(18,4),
TotalReturnedAmount numeric(18,4)
)
Insert Into #details
(
MonthlySalesHistoryID,
ItemID,
MeasurementUnitID,
QuantitySold,
QuantityReturned,
TotalSoldAmount,
TotalReturnedAmount
)
SELECT
#LastInsertID,
il.ItemID,
il.MeasurementUnitID,
SUM(il.Quantity) as QuantitySold,
ISNULL((SELECT SUM(Quantity) FROM InventoryLogs WHERE TransactionType = 15 AND CAST(InventoryLogDate as date) = #CurrentDate),0) as QuantityReturned,
SUM(il.ComputedCost) as TotalSoldAmount,
ISNULL((SELECT SUM(ComputedCost) FROM InventoryLogs WHERE TransactionType = 15 AND CAST(InventoryLogDate as date) = #CurrentDate),0) as TotalReturnedAmount
FROM InventoryLogs il
WHERE il.TransactionType = 9 AND CAST(InventoryLogDate as date) = #CurrentDate
GROUP BY il.ItemID, il.MeasurementUnitID
declare #count int = (SELECT COUNT(*) FROM #details)
declare #counter int = 0
WHILE(#count > #counter)
BEGIN
SET #counter = #counter + 1
SELECT * FROM #details d Where d.RowID = #counter
INSERT INTO MonthlySalesHistoryDetails
(
MonthlySalesHistoryID,
ItemID,
MeasurementUnitID,
QuantitySold,
QuantityReturned,
TotalSoldAmount,
TotalReturnedAmount
)
VALUES
(
//I want to get the values of my
//SELECT * FROM #details d Where d.RowID = #counter here..
)
END
thanks in advance....
I didn't know that it was possible to do this insert... I thought it was only good for declared table
INSERT INTO MonthlySalesHistoryDetails
(
MonthlySalesHistoryID,
ItemID,
MeasurementUnitID,
QuantitySold,
QuantityReturned,
TotalSoldAmount,
TotalReturnedAmount
)
SELECT
d.MonthlySalesHistoryID,
d.ItemID,
d.MeasurementUnitID,
d.QuantitySold,
d.QuantityReturned,
d.TotalSoldAmount,
d.TotalReturnedAmount
FROM #details d Where d.RowID = #counter

Haversine Formula works as Normal SQL but not in stored procedure

I am using haversine formula to find distance between users. It works well as a normal mysql piece of code. But when use the same in a stored procedure it not working and throws 0.00 distances. I don't know why?
This is the working code:
DROP TEMPORARY TABLE if exists temp_tab;
CREATE TEMPORARY TABLE temp_tab(temp_id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_fb_id bigint(20) unique,distance double(15,8) default NULL) CHARSET=utf8;
INSERT into temp_tab (user_fb_id, distance)
SELECT *
FROM (SELECT user_fb_id,
6371 * ACOS(SIN(RADIANS( 11.01684450 )) * SIN(RADIANS(`Latitude`)) + COS(RADIANS( 11.01684450 )) * COS(RADIANS(`Latitude`)) * COS(RADIANS(`Longitude`) - RADIANS( 76.95583210 ))) AS `distance`
FROM `user_login_log`
WHERE user_id <>'1831820984'
HAVING `distance` <= 50
ORDER BY `activity_at` DESC) as t1
GROUP BY user_fb_id;
SELECT * FROM temp_tab;
Normal SQL output:
Stored Procedure output:
Stored Procedure:
DELIMITER ;;
CREATE DEFINER=`up_beta`#`127.0.0.1` PROCEDURE `usp_geo`(user_id bigint(20),latitude double(15,8),longitude double(15,8), dist int(100),location longtext,page int(2),page_size int(2))
BEGIN
Declare limitStart int(10);
Declare limitEnd int(10);
SET #user_id=(SELECT user_id);
set #gen=(select gender from users where user_id=#user_id);
set #latitude = (SELECT latitude);
set #longitude = (SELECT longitude);
set #dist = (SELECT dist);
SET #location=(SELECT location);
set limitStart = ((page*page_size)-page_size);
set limitEnd = page_size ;
set #SNO = ((page - 1)*page_size);
IF #gen='male' then
set #gen='female';
else
set #gen='male';
end if;
DROP TEMPORARY TABLE if exists temp_tab;
CREATE TEMPORARY TABLE temp_tab(temp_id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_id bigint(20) unique,distance double(15,8) default NULL) CHARSET=utf8;
INSERT into temp_tab (user_id, distance)
SELECT * FROM (SELECT user_id, 6371 * ACOS(SIN(RADIANS( #latitude )) * SIN(RADIANS(Latitude)) + COS(RADIANS( #latitude )) * COS(RADIANS(Latitude)) * COS(RADIANS(Longitude) - RADIANS( #longitude ))) AS `distance` FROM `user_log` WHERE user_id <>#user_id HAVING `distance` <= #dist ORDER BY `activity_at` DESC) as t1
GROUP BY user_id;
SELECT * FROM temp_tab;
DROP TEMPORARY TABLE if exists search_tab;
CREATE TEMPORARY TABLE search_tab(temp_id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_id bigint(20) unique,name varchar(500),gender varchar(100),
town longtext,current_location longtext default NULL,is_in_app tinyint(4) default 0,distance double(15,8)) CHARSET=utf8;
INSERT INTO search_tab(user_id,name,gender,town,distance)
SELECT a.user_id, a.name,a.gender,a.home_town,b.distance FROM users a, temp_tab b WHERE a.user_id = b.user_id AND a.gender=#gen AND a.relationship_id NOT IN(2,3,4);
if #location<>'' AND #location<>NULL then
begin
set #city=(select concat('''','%',#location,'%',''''));
set #gender =(select concat('''',#gen,''''));
set #insert_sql = concat('INSERT IGNORE INTO search_tab(user_id,name,gender,town,location)
SELECT a.user_id, a.name,a.gender,a.home_town,b.current_location FROM users a, user_details b WHERE b.current_location LIKE ',#city,' AND a.id = b.user_id AND a.gender=',#gender,' AND a.relationship_id NOT IN(2,3,4)');
PREPARE stmt1 FROM #insert_sql;
EXECUTE stmt1;
end;
end if;
update search_tab set is_in_app=1 where user_fb_id in
(select user_id from users where access_token is not null);
select #a:=#a+1 sno,user_id,name,gender,town,current_location,is_in_app,distance
from search_tab ,(SELECT #a:= #SNO) AS a
limit limitStart,limitEnd;
select count(temp_id)as total_count from search_tab;
end;;
DELIMITER ;

case statement in where clause - SQL Server 2008

SELECT
PDADate, T.Merchandizer_ID, T.Merchandizer, Merchandizer_LoginName,
STORE_ID, STORE_CODE, STORE_NAME,
ACCOUNT_ID, ACCOUNT_NAME, Account_Store_Format_Id, Account_Store_Format,
StoreType_Id, StoreType, T.Listid, T.Listname,
T.TimeIn, T.TimeOut, T.PlannedDate, T.Reason, TaskCode, TotalTime
FROM
[dbo].Report_RD_Coverage T
INNER JOIN
#TempLocationH TL ON TL.LocationId=T.Location_Id
WHERE
CONVERT(Date, PDADate) Between (#Start_Date) AND Isnull(#End_Date, #CurrentDate)
AND T.Account_Id IN
(SELECT
CASE WHEN #Account_Id IS NULL THEN T.Account_Id
ELSE (SELECT * FROM UDF_SplitString(#Account_Id,','))
END
)
AND T.StoreType_Id IN
(SELECT
CASE WHEN #StoreType_Id IS NULL THEN T.StoreType_Id
ELSE (SELECT * FROM UDF_SplitString(#StoreType_Id,','))
END
)
AND T.Store_Id IN
(SELECT
CASE WHEN #Store_Id IS NULL THEN T.Store_Id
ELSE (SELECT * FROM UDF_SplitString(#Store_Id,','))
END
)
If #Account_Id, #StoreType_Id and #Store_Id are null the it should select all the ACCOUNT_ID, STORETYPE_ID and STORE_ID otherwise based on parameter value it should filter.
UDF_SplitString is the function to split up comma-separated strings, and its return value is a table like:
- 1
- 2
- 3
I'm getting this error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
CASE must return a scalar value, so try this variation instead:
select PDADate, T.Merchandizer_ID, T.Merchandizer, Merchandizer_LoginName, STORE_ID, STORE_CODE,
STORE_NAME, ACCOUNT_ID, ACCOUNT_NAME, Account_Store_Format_Id, Account_Store_Format,
StoreType_Id, StoreType, T.Listid, T.Listname, T.TimeIn, T.TimeOut, T.PlannedDate,
T.Reason, TaskCode, TotalTime
from [dbo].Report_RD_Coverage T
inner join #TempLocationH TL on TL.LocationId = T.Location_Id
where CONVERT(date, PDADate) between (#Start_Date)
and Isnull(#End_Date, #CurrentDate)
and (
#Account_Id is null
or T.Account_Id in (
select *
from UDF_SplitString(#Account_Id, ',')
)
)
and (
#StoreType_Id is null
or T.StoreType_Id in (
select *
from UDF_SplitString(#StoreType_Id, ',')
)
)
and (
#Store_Id is null
or T.Store_Id in (
select *
from UDF_SplitString(#Store_Id, ',')
) end
)
I tried this and reached very closer but you have to do something from what I found a link.
This is my try. the only thing you need to build is the #udf data.
declare #Store_Id INT;
declare #Account_Id INT;
DECLARE #UDF[9] OF VARCHAR(30);
set #Store_Id = 99 --NULL
set #Account_Id = 15
SET #UDF = '11,12,13,14,15,16'
SELECT #Account_Id AS ACID
WHERE CAST(#Account_Id AS VARCHAR(6)) IN (
CASE WHEN #Store_Id IS NULL THEN CAST(#Account_Id AS VARCHAR(6))
ELSE #UDF END
The link is at
http://www.codeproject.com/Questions/473174/CreateplusArrayplusinplusSqlplusServer
DECLARE #INSTR as VARCHAR(MAX)
SET #INSTR = '2,3,177,'
DECLARE #SEPERATOR as VARCHAR(1)
DECLARE #SP INT
DECLARE #VALUE VARCHAR(1000)
SET #SEPERATOR = ','
CREATE TABLE #tempTab (id int not null)
WHILE PATINDEX('%' + #SEPERATOR + '%', #INSTR ) <> 0
BEGIN
SELECT #SP = PATINDEX('%' + #SEPERATOR + '%',#INSTR)
SELECT #VALUE = LEFT(#INSTR , #SP - 1)
SELECT #INSTR = STUFF(#INSTR, 1, #SP, '')
INSERT INTO #tempTab (id) VALUES (#VALUE)
END
SELECT * FROM myTable WHERE id IN **(SELECT id FROM #tempTab)**
DROP TABLE #tempTab
you can extract for the sql in bold and the logic how to create temp table and its data and I hope you will get what you want.
> This is the my right solultion........now its working correctly
CREATE TABLE #Store_Id (StoreID varchar(20))
IF #Store_Id != '0'
BEGIN
INSERT INTO #Store_Id
SELECT data FROM UDF_SplitString(#Store_Id,',')
END
ELSE
BEGIN
INSERT INTO #Store_Id
SELECT '0'
END
CREATE TABLE #StoreType_Id (StoreTypeID varchar(20))
IF #StoreType_Id != '0'
BEGIN
INSERT INTO #StoreType_Id
SELECT data FROM UDF_SplitString(#StoreType_Id,',')
END
ELSE
BEGIN
INSERT INTO #StoreType_Id
SELECT '0'
END
CREATE TABLE #Account_Id (AccountID varchar(20))
IF #Account_Id != '0'
BEGIN
INSERT INTO #Account_Id
SELECT data FROM UDF_SplitString(#Account_Id,',')
END
ELSE
BEGIN
INSERT INTO #Account_Id
SELECT '0'
END
INSERT INTO #FinalTable(VisitDate,Merchandizer_Id,Merchandizer,MerchandizerLogin,StoreId,StoreCode,StoreName,AccountId,AccountName,
Account_Store_Format_Id,Account_Store_Format,StoreTypeId ,StoreType ,ListId ,ListName,TimeIn ,TimeOut,PlannedDate ,Reason ,TaskCode,TotalTime)
SELECT Visit_Date,T.Merchandizer_ID,T.Merchandizer,Merchandizer_LoginName,STORE_ID,STORE_CODE,STORE_NAME,ACCOUNT_ID,ACCOUNT_NAME,
Account_Store_Format_Id,Account_Store_Format,StoreType_Id,
StoreType,T.Listid,T.Listname,T.TimeIn,T.TimeOut,T.PlannedDate,T.Reason,TaskCode,TotalTime
FROM [dbo].Report_RD_Coverage T
INNER JOIN #TempLocationH TL ON TL.LocationId=T.Location_Id
INNER JOIN #Store_Id on CONVERT(VARCHAR,t.Store_Id) = CASE WHEN #Store_Id = '0' THEN convert(VARCHAR,t.Store_Id) ELSE StoreID END
INNER JOIN #StoreType_Id on CONVERT(VARCHAR,t.StoreType_Id) = CASE WHEN #StoreType_Id = '0' THEN convert(VARCHAR,t.StoreType_Id) ELSE StoreTypeID END
INNER JOIN #Account_Id on CONVERT(VARCHAR,t.Account_Id) = CASE WHEN #Account_Id = '0' THEN convert(VARCHAR,t.Account_Id) ELSE AccountID END
WHERE CONVERT(Date,PDADate) Between #Start_Date AND #End_Date