Optional OrderBy parameter in MySql Stored Procedure - mysql

I'm being passed in an optional OrderBy value that should default to DESC, and if set to false, should ORDER BY ASC. I'm not really sure how to do this ordering based off the input. Here is what I have currently:
CREATE DEFINER=`app`#`%` PROCEDURE `BLAH`(
pWithdrawalTransactionId INT,
pLimit INT,
pSortDescending TINYINT
)
BEGIN
DECLARE vLimit INT DEFAULT COALESCE(pLimit, 100);
DECLARE vSort TINYINT DEFAULT COALESCE(pSortDescending, 1);
SELECT
f.WithdrawalFulfillmentId, f.PaymentStatusId, f.PaymentProcessorId, f.PaymentTypeId, r.Amount, r.RequestedAmount, r.NativeAmount, r.NativeRequestedAmount, r.RefundTransactionId, r.UpdatedDate
FROM
FinOps.UserWithdrawalFulfillment f
INNER JOIN
FinOps.UserRefundTransaction r ON f.RefundTransactionId = r.RefundTransactionId
WHERE
f.WithdrawalTransactionId = pWithdrawalTransactionId
LIMIT
vLimit;
END

So the correct way to do this would be like this:
CREATE DEFINER=`app`#`%` PROCEDURE `BLAH`(
pWithdrawalTransactionId INT,
pLimit INT,
pSortDescending TINYINT
)
BEGIN
DECLARE vLimit INT DEFAULT COALESCE(pLimit, 100);
DECLARE vSort TINYINT DEFAULT COALESCE(pSortDescending, 1);
SELECT
f.WithdrawalFulfillmentId, f.PaymentStatusId, f.PaymentProcessorId, f.PaymentTypeId, r.Amount, r.RequestedAmount, r.NativeAmount, r.NativeRequestedAmount, r.RefundTransactionId, r.UpdatedDate
FROM
FinOps.UserWithdrawalFulfillment f
INNER JOIN
FinOps.UserRefundTransaction r ON f.RefundTransactionId = r.RefundTransactionId
WHERE
f.WithdrawalTransactionId = pWithdrawalTransactionId
ORDER BY CASE WHEN pSortDescending = 1 THEN WithdrawalFulfillmentId * -1 ELSE WithdrawalFulfillmentId END ASC
LIMIT
vLimit;
END

Related

filter ids by comma separated input ids MYSQL [duplicate]

can anybody tell me how to implement a split function in mysql which behaves like Javascript split.
I want a function like this
SELECT Split('a,b,c,d', ',') AS splitted
Which give result like
splitted
--------------
a
b
c
d
Can anybody help me?
I saw some answers here, and somewhere else, but those functions need the position of string to be returned, which I don't want/have
Thank you
It is possible:
-- Preparation
CREATE TABLE tb_Digits (d int(11) UNSIGNED NOT NULL PRIMARY KEY);
INSERT tb_Digits VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
INSERT IGNORE tb_Digits
SELECT o1.d+o2.d*10+o3.d*100+o4.d*1000 d FROM tb_Digits o4, tb_Digits o3, tb_Digits o2, tb_Digits o1;
CREATE PROCEDURE pc_splitStr(IN in_string TEXT, IN in_separator CHAR(1))
COMMENT 'Use (SELECT word FROM return_splitStr) para ver o resultado'
BEGIN
DECLARE o_limit INT(11) UNSIGNED DEFAULT LENGTH(in_string)-LENGTH(REPLACE(in_string,in_separator,''))+1;
DROP TABLE IF EXISTS return_splitStr;
CREATE TEMPORARY TABLE return_splitStr (word TEXT);
INSERT return_splitStr
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(in_string, in_separator, d.d), in_separator, -1)
FROM tb_Digits d
WHERE d.d>0 AND d.d<=o_limit;
END;
-- Execution
CALL pc_splitStr('a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z',',');
SELECT word FROM return_splitStr;
You can create a function and return the specific result you are waiting for.
here is an example with multi ids in one column extracted and queried to get the specific values :
DROP FUNCTION IF EXISTS getValuesByOptionIds;
DELIMITER $$
CREATE FUNCTION getValuesByOptionIds
(
optionIds VARCHAR(255)
)
RETURNS VARCHAR(255)
DETERMINISTIC
BEGIN
DECLARE iter INTEGER DEFAULT 0;
DECLARE result VARCHAR(255) DEFAULT '';
DECLARE previousIter VARCHAR(255) DEFAULT '';
iters: WHILE LENGTH(SUBSTRING_INDEX(optionIds, ',', iter + 1)) != LENGTH(previousIter) DO
SET iter = iter + 1;
SET previousIter = SUBSTRING_INDEX(optionIds, ',', iter);
IF iter = 1 THEN
SET result = (select tmp.value from eav_attribute_option_value tmp where tmp.option_id = SUBSTRING_INDEX(optionIds, ',', iter));
ELSEIF iter > 1 THEN
SET result = concat(result, ',', (select tmp.value from eav_attribute_option_value tmp where tmp.option_id = SUBSTRING_INDEX(SUBSTRING_INDEX(optionIds, ',', iter), ',', -1)));
END IF;
END WHILE iters;
RETURN result;
END$$
DELIMITER ;

String Split function in MySQL

can anybody tell me how to implement a split function in mysql which behaves like Javascript split.
I want a function like this
SELECT Split('a,b,c,d', ',') AS splitted
Which give result like
splitted
--------------
a
b
c
d
Can anybody help me?
I saw some answers here, and somewhere else, but those functions need the position of string to be returned, which I don't want/have
Thank you
It is possible:
-- Preparation
CREATE TABLE tb_Digits (d int(11) UNSIGNED NOT NULL PRIMARY KEY);
INSERT tb_Digits VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
INSERT IGNORE tb_Digits
SELECT o1.d+o2.d*10+o3.d*100+o4.d*1000 d FROM tb_Digits o4, tb_Digits o3, tb_Digits o2, tb_Digits o1;
CREATE PROCEDURE pc_splitStr(IN in_string TEXT, IN in_separator CHAR(1))
COMMENT 'Use (SELECT word FROM return_splitStr) para ver o resultado'
BEGIN
DECLARE o_limit INT(11) UNSIGNED DEFAULT LENGTH(in_string)-LENGTH(REPLACE(in_string,in_separator,''))+1;
DROP TABLE IF EXISTS return_splitStr;
CREATE TEMPORARY TABLE return_splitStr (word TEXT);
INSERT return_splitStr
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(in_string, in_separator, d.d), in_separator, -1)
FROM tb_Digits d
WHERE d.d>0 AND d.d<=o_limit;
END;
-- Execution
CALL pc_splitStr('a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z',',');
SELECT word FROM return_splitStr;
You can create a function and return the specific result you are waiting for.
here is an example with multi ids in one column extracted and queried to get the specific values :
DROP FUNCTION IF EXISTS getValuesByOptionIds;
DELIMITER $$
CREATE FUNCTION getValuesByOptionIds
(
optionIds VARCHAR(255)
)
RETURNS VARCHAR(255)
DETERMINISTIC
BEGIN
DECLARE iter INTEGER DEFAULT 0;
DECLARE result VARCHAR(255) DEFAULT '';
DECLARE previousIter VARCHAR(255) DEFAULT '';
iters: WHILE LENGTH(SUBSTRING_INDEX(optionIds, ',', iter + 1)) != LENGTH(previousIter) DO
SET iter = iter + 1;
SET previousIter = SUBSTRING_INDEX(optionIds, ',', iter);
IF iter = 1 THEN
SET result = (select tmp.value from eav_attribute_option_value tmp where tmp.option_id = SUBSTRING_INDEX(optionIds, ',', iter));
ELSEIF iter > 1 THEN
SET result = concat(result, ',', (select tmp.value from eav_attribute_option_value tmp where tmp.option_id = SUBSTRING_INDEX(SUBSTRING_INDEX(optionIds, ',', iter), ',', -1)));
END IF;
END WHILE iters;
RETURN result;
END$$
DELIMITER ;

Mysql Table function and view returns null value

I really don't know why my function and view in phpmyadmin returns null instead of DATETIME.
This is my function:
DELIMITER $$
CREATE FUNCTION `return_file`( name varchar(10), number int )
RETURNS datetime
DETERMINISTIC
BEGIN DECLARE transdate DATETIME;
SET trans_date = (SELECT `date` from `sample_table` WHERE `name_ref` = name and `ref_number` = number and `type` = 10);
RETURN trans_date;
END$$
DELIMITER ;
While this is my view:
CREATE VIEW getsME as
SELECT id,type,date,name_ref,ref_number,return_file(name_ref,ref_number) as transDate
FROM sample_table
WHERE type= 11
ORDER BY id ASC

Update row null fields with values from similar rows (same "key")

My question is kind of hard to explain in title so I'll show the data and goal.
There is a MySQL table with following structure:
CREATE TABLE customerProjectData(
idCustomer INT NOT NULL,
idProject INT DEFAULT NULL,
comePersons SMALLINT DEFAULT NULL,
comePairs SMALLINT DEFAULT NULL,
comment VARCHAR(255) DEFAULT NULL,
idCity INT DEFAULT NULL,
idStreet INT DEFAULT NULL,
name VARCHAR(64) DEFAULT NULL,
surname VARCHAR(64) DEFAULT NULL,
homeNum VARCHAR(10) DEFAULT NULL,
postCode CHAR(6) DEFAULT NULL,
postCity VARCHAR(64) DEFAULT NULL,
cellPhone VARCHAR(12) DEFAULT NULL
)
The thing is, there shold be also PRIMARY KEY(idCustomer, idProject) defined and it's not. As a result There are kind of duplicates (with the same primary key) but with different data.
I could run ALTER IGNORE TABLE but data loss would probably be unacceptable and unpredicatable. Finally we decided to try to fill null fields with values from duplicates if they contain data and after that run the ALTER IGNORE TABLE. Much less data will be lost that way and it's acceptable in this case (it's better than leaving it as it is now in longer time perspective).
The question is how to fill those fields from each duplicate.
Here is a rough try.
First try to find out the no. of rows which have the same key.
<?php
// $link is the database identifier
$sql = 'SELECT COUNT(*) AS num, * FROM `customerProjectData` GROUP BY `idCustomer`, `idProject` HAVING COUNT(*) > 1 ORDER BY COUNT(*) ASC;';
$run = mysql_query( $sql, $link );
$rows = array();
if( $run && mysql_num_rows( $run ) ) {
while( ( $fetch = mysql_fetch_assoc( $run ) ) !== false ) {
$rows[] = $fetch;
}
}
?>
Now $rows contains a list of all rows which have the same key and a count of how many times this key has been repeated in the table.
You can write a function which then iterates count times and see which rows has the complete data and use that to populates other records with this record's data.
A bit of trial and error.
I used #web-nomad suggestion and did something similar, but in sql procedure:
DROP PROCEDURE IF EXISTS correctCPD$$
CREATE PROCEDURE correctCPD()
BEGIN
DECLARE currentCustomerId INT;
DECLARE currentProjectId INT;
DECLARE cur_idCustomer INT;
DECLARE cur_idProject INT;
DECLARE cur_comePersons SMALLINT;
DECLARE cur_comePairs SMALLINT;
DECLARE cur_comment VARCHAR(255);
DECLARE cur_idCity INT;
DECLARE cur_idStreet INT;
DECLARE cur_name VARCHAR(64);
DECLARE cur_surname VARCHAR(64);
DECLARE cur_homeNum VARCHAR(10);
DECLARE cur_postCode CHAR(6);
DECLARE cur_postCity VARCHAR(64);
DECLARE cur_cellPhone VARCHAR(12);
CREATE TEMPORARY TABLE ids (
idCustomer INT,
idProject INT
) ENGINE = InnoDB;
INSERT INTO ids
SELECT idCustomer, idProject FROM customerprojectdata group by idCustomer, idProject having count(*) > 1;
BLOCK1: BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE itemCur CURSOR FOR SELECT idCustomer, idProject FROM ids;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN itemCur;
itemCurLoop: LOOP
FETCH itemCur INTO currentCustomerId, currentProjectId;
IF done THEN
LEAVE itemCurLoop;
END IF;
BLOCK2: BEGIN
DECLARE doneIn INT DEFAULT FALSE;
DECLARE cpdCur CURSOR FOR SELECT idCustomer, idProject, comePersons, comePairs, comment, idCity, idStreet, name, surname, homeNum, postCode, postCity, cellPhone FROM customerProjectData WHERE idCustomer = currentCustomerId AND idProject = currentProjectId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET doneIn = TRUE;
OPEN cpdCur;
cpdCurLoop: LOOP
FETCH cpdCur INTO
cur_idCustomer, cur_idProject, cur_comePersons, cur_comePairs,
cur_comment, cur_idCity, cur_idStreet, cur_name, cur_surname,
cur_homeNum, cur_postCode, cur_postCity, cur_cellPhone;
IF doneIn THEN
LEAVE cpdCurLoop;
END IF;
UPDATE CustomerProjectData SET
comePersons = IF((comePersons IS NULL OR comePersons = '') AND cur_comePersons > 0, cur_comePersons, comePersons),
comePairs = IF((comePairs IS NULL OR comePairs = '') AND cur_comePairs > 0, cur_comePairs, comePairs),
comment = IF((comment IS NULL OR comment = '') AND cur_comment > 0, cur_comment, comment),
idCity = IF((idCity IS NULL AND idStreet IS NULL) AND cur_idCity > 0, cur_idCity, idCity),
idStreet = IF(((idCity IS NULL OR idCity = cur_idCity) AND idStreet IS NULL) AND cur_idStreet > 0, cur_idStreet, idStreet),
name = IF((name IS NULL OR name = '') AND cur_name > 0, cur_name, name),
surname = IF((surname IS NULL OR surname = '') AND cur_surname > 0, cur_surname, surname),
homeNum = IF((homeNum IS NULL OR homeNum = '') AND cur_homeNum > 0, cur_homeNum, homeNum),
postCode = IF((postCode IS NULL OR postCode = '') AND cur_postCode > 0, cur_postCode, postCode),
postCity = IF((postCity IS NULL OR postCity = '') AND cur_postCity > 0, cur_postCity, postCity),
cellPhone = IF((cellPhone IS NULL OR cellPhone = '') AND cur_cellPhone > 0, cur_cellPhone, cellPhone)
WHERE idCustomer = currentCustomerId AND idProject = currentProjectId;
END LOOP;
CLOSE cpdCur;
END BLOCK2;
END LOOP;
CLOSE itemCur;
END BLOCK1;
DROP TEMPORARY TABLE ids;
END$$
Thanks for help!

Need help in converting INSERT\UPDATE to MERGE

Is this a good candidate for a MERGE command?
Must the source data also be another table or can it be variables that are passed?
If it must be a table, is inserting the passed variables into a temp table sane?
Could you help me with the syntax?
CREATE PROCEDURE [dbo].[usp_ConvertToMerge]
#GL_DT date
,#SRC_SYS_ID varchar(60)
,#MLR_SRC_SYS_CD char(3)
,#TRSRY_FEED_DT date
,#Data varchar(20)
AS
BEGIN
IF NOT EXISTS (SELECT
#GL_DT
FROM
MLR_REBATE_IBOR_INFO_2
WHERE
[GL_DT] = #GL_DT
AND [SRC_SYS_ID] = #SRC_SYS_ID
AND [MLR_SRC_SYS_CD] = #MLR_SRC_SYS_CD
AND [TRSRY_FEED_DT] = #TRSRY_FEED_DT)
BEGIN
INSERT INTO [dbo].[MLR_REBATE_IBOR_INFO_2]
([GL_DT],
[SRC_SYS_ID],
[MLR_SRC_SYS_CD],
[TRSRY_FEED_DT],
[Data])
SELECT
#GL_DT
,#SRC_SYS_ID
,#MLR_SRC_SYS_CD
,#TRSRY_FEED_DT
,#Data
END
ELSE
BEGIN
UPDATE [dbo].[MLR_REBATE_IBOR_INFO_2]
SET [Data] = #Data
WHERE [GL_DT] = #GL_DT
AND [SRC_SYS_ID] = #SRC_SYS_ID
AND [MLR_SRC_SYS_CD] = #MLR_SRC_SYS_CD
AND [TRSRY_FEED_DT] = #TRSRY_FEED_DT
END
END
GO
I think I did it:
CREATE PROCEDURE MyMergeTest
#GL_DT date
,#SRC_SYS_ID char(20)
,#MLR_SRC_SYS_CD char(3)
,#TRSRY_FEED_DT date
,#Data varchar(20)
AS
BEGIN
MERGE MLR_REBATE_IBOR_INFO_2 AS target
USING
(
SELECT
#GL_DT
,#SRC_SYS_ID
,#MLR_SRC_SYS_CD
,#TRSRY_FEED_DT
,#Data
) AS source
(
GL_DT
,SRC_SYS_ID
,MLR_SRC_SYS_CD
,TRSRY_FEED_DT
,Data
)
ON (
target.GL_DT = source.GL_DT AND
target.SRC_SYS_ID = source.SRC_SYS_ID AND
target.MLR_SRC_SYS_CD = source.MLR_SRC_SYS_CD AND
target.TRSRY_FEED_DT = source.TRSRY_FEED_DT
)
WHEN MATCHED THEN
UPDATE SET Data = source.Data
WHEN NOT MATCHED THEN
INSERT
(
[GL_DT],
[SRC_SYS_ID],
[MLR_SRC_SYS_CD],
[TRSRY_FEED_DT],
[Data]
)
VALUES
(
[GL_DT], --<<it looks like these can eiether be the variable eg, #GL_DT, or prefixed by 'source.'
[SRC_SYS_ID],
[MLR_SRC_SYS_CD],
[TRSRY_FEED_DT],
[Data]
);
END