Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I know my questions sounds silly , but i'm not able to run my code because of that problem , all my procedure is correct , my only one problem is that i'm not able to use syntax that contains a string which is :
SET #query = CONCAT(#query, ' WHERE i.active=T');
I tried to use + between the apostrophe and . , however in all cases not working...
here is the full procedure
CREATE PROCEDURE stocktakess()
BEGIN
DECLARE wid INT;
DECLARE wname VARCHAR(20);
DECLARE query TEXT DEFAULT '';
DECLARE finished INT DEFAULT 0;
DECLARE whouse_cursor CURSOR FOR SELECT Id, name FROM warehouse WHERE Id IN (1,2,3,5,8);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN whouse_cursor;
SET #query = 'SELECT i.code,i.code2,i.description';
get_whouse: LOOP
FETCH whouse_cursor INTO wid, wname;
IF finished = 1 THEN
LEAVE get_whouse;
END IF;
SET #query = CONCAT(#query, ', SUM(CASE WHEN m.warehouseID=', wid, ' THEN COALESCE(m.qtyin, 0) - COALESCE(m.qtyout, 0) ELSE 0 END) AS `', wname, '`');
END LOOP get_whouse;
SET #query = CONCAT(#query, ' FROM items i LEFT JOIN itemmovement m ON m.itemid = i.Id');
SET #query = CONCAT(#query, ' WHERE i.active=T');
SET #query = CONCAT(#query, ' GROUP BY i.Id');
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
CREATE PROCEDURE stocktakess()
BEGIN
DECLARE wid INT;
DECLARE wname VARCHAR(20);
DECLARE query TEXT DEFAULT '';
DECLARE finished INT DEFAULT 0;
DECLARE whouse_cursor CURSOR FOR SELECT Id, name FROM warehouse WHERE Id IN (1,2,3,5,8);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN whouse_cursor;
SET #query = 'SELECT i.code,i.code2,i.description';
get_whouse: LOOP
FETCH whouse_cursor INTO wid, wname;
IF finished = 1 THEN
LEAVE get_whouse;
END IF;
SET #query = CONCAT(#query, ', SUM(CASE WHEN m.warehouseID=', wid, ' THEN COALESCE(m.qtyin, 0) - COALESCE(m.qtyout, 0) ELSE 0 END) AS `', wname, '`');
END LOOP get_whouse;
SET #query = CONCAT(#query, ' FROM items i LEFT JOIN itemmovement m ON m.itemid = i.Id');
SET #query = CONCAT(#query, ' WHERE i.active=\'T\'');
SET #query = CONCAT(#query, ' GROUP BY i.Id');
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Related
I got a problem while executing my stored procedure in web service that I create in PHP language. If I execute the SP below directly in SQL Server Management Studio, it works perfectly. But when I execute the SP from my web service with PHP, it only executes some of the data in the looping I made in SP.
I got a service table as a master room data. In that SP below, I would like to check is the room available in a date range that I input to stored procedure one by one.
For example, I got 6 rooms in service table, and I want to check it one by one in looping with cursor. When I execute the SP in web service, it only execute 4 rooms in looping, but if I execute the SP in management studio directly, it works perfectly.
Can somebody help me to solve this problem?
Thank you.
Create Procedure GetAvailableRoom
#Date1 Datetime,
#Date2 Datetime,
#UserID Varchar(15)
AS
Begin
Delete From Room_Availability Where UserID = #UserID
Declare #KL Varchar(50)
Declare Cursor_RA Cursor For SELECT Service_Code FROM Services Where Status = 'ROOM' Order By Service_Code
Open Cursor_RA
Fetch Next From Cursor_RA Into #KL
While ##FETCH_STATUS = 0
Begin
print #KL
Declare #MyDate DateTime
Set #MyDate = #Date1
Declare #Diff Int
Set #Diff = DateDiff(Day, #Date1, #Date2)
Declare #Counter Int
Set #Counter = 0
print #MyDate
print #Diff
print #Counter
While (#Counter <= #Diff)
Begin
Print 'My Date is ' + Convert(Varchar, format(#MyDate,'yyyy-MM-dd'))
if exists(SELECT #KL, format(#MyDate,'yyyy-MM-dd 00:0:00'), Customers.Name + ' | ' + Customers.HP, #UserID
FROM Reservation INNER JOIN Reservation_Details ON Reservation.Reservation_Code = Reservation_Details.Reservation_Code
INNER JOIN Customers ON Reservation.Customer_ID = Customers.Customer_ID
WHERE Reservation_Details.Kode_Service = #KL AND
Reservation_Details.Checkin <= format(#MyDate,'yyyy-MM-dd 23:59:59') AND
Reservation_Details.Checkout >= format(#MyDate,'yyyy-MM-dd 00:0:00'))
Begin
print 'exists'
Insert Into Room_Availability (Service_Code,Service_Date,Customer,UserID)
SELECT #KL, format(#MyDate,'yyyy-MM-dd 00:0:00'), Customers.Name + ' | ' + Customers.HP, #UserID
FROM Reservation INNER JOIN Reservation_Details ON Reservation.Reservation_Code = Reservation_Details.Reservation_Code
INNER JOIN Customers ON Reservation.Customer_ID = Customers.Customer_ID
WHERE Reservation_Details.Service_Code = #KL AND
Reservation_Details.Checkin <= format(#MyDate,'yyyy-MM-dd 23:59:59') AND
Reservation_Details.Checkout >= format(#MyDate,'yyyy-MM-dd 00:0:00')
End
Else
Begin
print 'not exists'
Insert Into Room_Availability (Service_Code,Service_Date,Customer,UserID)
Values(#KL, format(#MyDate,'yyyy-MM-dd 00:0:00'), 'EMPTY', #UserID)
End
Set #MyDate = dateadd(dd,1,#MyDate)
Set #Counter = #Counter + 1
End
Fetch Next From Cursor_RA Into #KL
End
Close Cursor_RA
Deallocate Cursor_RA
End
This is the web service code.
<?php
include 'settings.php';
ini_set('mssql.connect_timeout',15);
$sqlconn = sqlsrv_connect($serverName, $connectionOptions);
if ($sqlconn === false)
die(FormatErrors(sqlsrv_errors()));
$tsql = "GetAvailableRoom '" . $_POST['Date1'] . "','" . $_POST['Date2'] . "','" . $_POST['UserID'] . "'";
//echo $tsql;
$cursorType = array("Scrollable" => SQLSRV_CURSOR_DYNAMIC);
$getexec = sqlsrv_query($sqlconn, $tsql, null, $cursorType);
if ($getexec === false)
die(FormatErrors(sqlsrv_errors()));
sqlsrv_free_stmt($getexec);
sqlsrv_close($sqlconn);
We have been stumped with this all morning.
I have an MSSQL stored proc which processes some records. Each record generates an email with dynamic content, and this is populated from another stored proc.
So the first stored proc has a cursor, and each row is processed resulting in a call to another stored proc, which itself has a cursor to loop through. The first stored proc has no output parameters or returned values, etc, while the second uses output parameters to return fields to the first proc.
This works fine from Datagrip.
Calling this from php using PDO (or using other drivers) it fails to run fully. It would produce a small batch of records then stop (tends to be either 5, 9, 13 or 45 - has changed as we have experimented with difference solutions).
We have managed to get it to run now using PDOStatement::nextRowset . We use a query of the first stored proc and then using while ( $stmt->nextRowset() ) ; to loop through the (non existent / unwanted) row sets.
This works. But as the first stored proc isn't returning anything (just that pdo seems to want to process some kind of internal result set) this seems very dirty and inefficient.
Is there an alternative? Possibly a parameter to pass to pdo, or a setting within the stored proc?
Below there is some simplified code to show how things interact.
PHP calling script.
<?php
$emailRepository = new EmailRepository(hostname, port, dbname, username, password);
$ret = $emailRepository->sendRenewalEmails();
class EmailRepository
{
public function __construct($hostname, $port, $dbname, $username, $password)
{
$this->hostname = $hostname;
$this->port = $port;
$this->dbname = $dbname;
$this->username = $username;
$this->password = $password;
$this->connect();
}
private function connect()
{
try {
$this->db = new PDO ("sqlsrv:Server=$this->hostname,$this->port;Database=$this->dbname", $this->username, $this->password);
$this->db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
} catch (PDOException $e) {
var_dump("Failed to get DB handle: " . $e->getMessage());
}
}
public function sendRenewalEmails()
{
try {
$stmt = $this->db->prepare("EXEC membership_queue_renewal_emails");
$stmt->execute();
do {
echo '>';
} while($stmt->nextRowset());
return true;
} catch (Exception $e) {
echo $e->getMessage();
}
}
}
First stored proc (heavily cut down)
CREATE PROCEDURE [dbo].[queue_renewal_emails]
AS
BEGIN
DECLARE #curr_member_cursor CURSOR;
DECLARE #curr_club_cursor CURSOR;
DECLARE #g_personid INT;
DECLARE #g_emailTemplateId INT;
DECLARE #g_email_subject VARCHAR(200);
DECLARE #g_email_html VARCHAR(max);
DECLARE #g_email_plain VARCHAR(max);
DECLARE #g_personEmail VARCHAR(128);
SET #curr_club_cursor = CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT DISTINCT
bgemailTemplate.bgemte_name,
bgemailTemplate.bgemte_emailtemplateid,
vpersonpe.pers_emailaddress,
vpersonpe.pers_personId,
FROM company WITH(NOLOCK)
INNER JOIN complink WITH(NOLOCK) ON complink.clli_companyid = complink.Comp_CompanyId
AND complink.clli_Deleted is null
INNER JOIN vpersonpe WITH(NOLOCK) ON vpersonpe.pers_personId = complink.clli_personId
INNER JOIN bgemailTemplate WITH(NOLOCK) ON bgemailTemplate.bgemte_Deleted IS NULL
WHERE vPersonPE.pers_deleted IS NULL
AND company.comp_deleted IS NULL
AND vPersonPE.pers_parentid IS NULL
AND vpersonpe.pers_status NOT IN ('Cancelled','Expired','Suspended','Awaiting Approval','Declined','On hold','Revoked','Expelled');
-- loop through each course
OPEN #curr_club_cursor;
FETCH NEXT FROM #curr_club_cursor INTO #g_email_subject, #g_emailTemplateId, #g_personEmail, #g_personid;
WHILE ##fetch_status = 0
BEGIN
EXEC dbo.populateEmail #g_emailtemplateid /* Email template id */,
#g_email_plain OUTPUT /* Plain text email to have the placeholders replaced */,
#g_email_subject OUTPUT,
#g_personid ;
FETCH NEXT FROM #curr_club_cursor INTO #g_email_subject, #g_emailTemplateId, #g_personEmail, #g_personid;
END
CLOSE #curr_club_cursor
DEALLOCATE #curr_club_cursor
END
go
Second stored proc (heavily cut down).
CREATE PROCEDURE [dbo].[populateEmail]
#p_emailtemplateid INT,
#p_email_text VARCHAR(max) OUTPUT,
#p_email_subject VARCHAR(200) OUTPUT,
#p_person_id INT
AS
BEGIN
SET NOCOUNT ON;
-- CURSORs
DECLARE #curr_field_cursor CURSOR;
DECLARE #g_email_plain VARCHAR(MAX) = '';
DECLARE #g_email_subject VARCHAR(200) = '';
DECLARE #g_emte_emailtemplateid INT;
DECLARE #g_EmailPlaceholderId INT;
DECLARE #g_place_holder VARCHAR(128);
DECLARE #g_source_column VARCHAR(128);
DECLARE #g_prev_source_query_num INT;
DECLARE #g_source_query_num INT;
-- Variables to read results into from each query
DECLARE #g_q11_comp_name VARCHAR(180);
DECLARE #g_q11_comp_website VARCHAR(300);
DECLARE #g_q11_comp_pers_salutation VARCHAR(30);
DECLARE #g_q11_comp_pers_firstname VARCHAR(90);
DECLARE #g_q11_comp_pers_lastname VARCHAR(120);
-- Start processing
SET #p_email_text = '';
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET #curr_field_cursor = CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT a.emte_emailtemplateid,
b.emtl_EmailPlaceholderId,
c.empl_PlaceHolder,
c.empl_SourceQueryNum,
c.empl_SourceColumn,
a.emte_plaintextemail,
a.emte_subject
FROM EmailTemplate a with (nolock)
LEFT OUTER JOIN EmailTemplateLink b with (nolock)
ON a.emte_emailtemplateid = b.emtl_EmailTemplateId
LEFT OUTER JOIN EmailPlaceholder c with (nolock)
ON b.emtl_EmailPlaceholderId = c.empl_EmailPlaceholderID
WHERE a.emte_emailtemplateid = #p_emailtemplateid
ORDER BY c.empl_SourceQueryNum;
-- Loop through each required place holder for the passed email template.
SET #g_prev_source_query_num = 0;
OPEN #curr_field_cursor
FETCH NEXT FROM #curr_field_cursor INTO #g_emte_emailtemplateid, #g_EmailPlaceholderId, #g_place_holder, #g_source_query_num, #g_source_column, #g_email_plain, #g_email_subject;
WHILE ##fetch_status = 0
BEGIN
IF #g_prev_source_query_num = 0
BEGIN
SET #p_email_text = #g_email_plain;
SET #p_email_subject = #g_email_subject;
END;
IF #g_source_query_num = 11
BEGIN
IF #g_prev_source_query_num != #g_source_query_num
BEGIN
SELECT #g_q11_comp_name = comp_name,
#g_q11_comp_website = comp_website,
#g_q11_comp_pers_salutation = Pers_Salutation,
#g_q11_comp_pers_firstname = pers_firstname,
#g_q11_comp_pers_lastname = pers_lastname
FROM company with (nolock)
LEFT OUTER JOIN vPerson with (nolock) ON company.Comp_PrimaryPersonId = vPerson.Pers_PersonId
LEFT OUTER JOIN address with (nolock) ON company.Comp_PrimaryAddressId = address.Addr_AddressId
WHERE company.Comp_CompanyId = #p_person_id;
END;
IF #g_source_column = 'comp_name'
BEGIN
SET #p_email_text = REPLACE(#p_email_text, #g_place_holder, COALESCE(#g_q11_comp_name, ''));
SET #p_email_subject = REPLACE(#p_email_subject, #g_place_holder, COALESCE(#g_q11_comp_name, ''));
END;
ELSE IF #g_source_column = 'comp_website'
BEGIN
SET #p_email_text = REPLACE(#p_email_text, #g_place_holder, COALESCE(#g_q11_comp_website, ''));
SET #p_email_subject = REPLACE(#p_email_subject, #g_place_holder, COALESCE(#g_q11_comp_website, ''));
END;
ELSE IF #g_source_column = 'comp_primary_person_firstname'
BEGIN
SET #p_email_text = REPLACE(#p_email_text, #g_place_holder, COALESCE(#g_q11_comp_pers_salutation, ''));
SET #p_email_subject = REPLACE(#p_email_subject, #g_place_holder, COALESCE(#g_q11_comp_pers_salutation, ''));
END;
ELSE IF #g_source_column = 'comp_primary_person_salutation'
BEGIN
SET #p_email_text = REPLACE(#p_email_text, #g_place_holder, COALESCE(#g_q11_comp_pers_firstname, ''));
SET #p_email_subject = REPLACE(#p_email_subject, #g_place_holder, COALESCE(#g_q11_comp_pers_firstname, ''));
END;
ELSE IF #g_source_column = 'comp_primary_person_lastname'
BEGIN
SET #p_email_text = REPLACE(#p_email_text, #g_place_holder, COALESCE(#g_q11_comp_pers_lastname, ''));
SET #p_email_subject = REPLACE(#p_email_subject, #g_place_holder, COALESCE(#g_q11_comp_pers_lastname, ''));
END;
END;
SET #g_prev_source_query_num = #g_source_query_num;
FETCH NEXT FROM #curr_field_cursor INTO #g_emte_emailtemplateid, #g_EmailPlaceholderId, #g_place_holder, #g_source_query_num, #g_source_column, #g_email_plain, #g_email_subject;
END;
CLOSE #curr_field_cursor
DEALLOCATE #curr_field_cursor
END
go
as the first stored proc isn't returning anything ... is there an alternative to while ( $stmt->nextRowset() ) ;
I'ts probably the rowcount messages causing the client to see empty rowsets. Add SET NOCOUNT ON as the first line of each stored procedure.
I have some problem when converting rows into column in codeigniter, i have a sql query to convert row into column using group_concat...
this is my query
SET ##group_concat_max_len = 5000;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(idPertanyaan = ''',
idPertanyaan,
''', jawaban, NULL)) AS ',
idPertanyaan
)
) INTO #sql
FROM kuesioner;
SET #sql = CONCAT('SELECT idmember, ', #sql, ' FROM kuesioner GROUP BY idmember');
PREPARE stmt FROM #sql;
EXECUTE stmt;
I can't turn that query into codeigniter model
please tell me create model with this query or how to convert dynamic row into column... thanks
If you create a stored procedure in your database, then within your Model you can do this:
public function yourFunction() {
$query = $this->db->query("CALL `your_stored_procedure()`");
return $query->result_array();
}
I have a stored procedure in MySQL. I call my procedure in php as
$qry = $mysqli->prepare("CALL seen_table()");
i tried to get the resulting rows by
$row = $qry->num-rows;
but its resulting 0 even there is a resulting set.Then I tried also to put output parameter in my procedure where in inside of my proc is ...
SELECT COUNT(*) INTO cnt FROM TBL
...then this is my codes
$qry = $mysqli->prepare("CALL seen_table(#cnt)");
$qry1 = $mysqli->query("SELECT #cnt");
$row = $qry1->num_rows;
then now its always results 1 even there is no count. when i try to execute CALL and SELECT #cnt in Mysql . if there is no count. the result will be
|#cnt|
|(null)|
does null really count as one?please help. thanks a lot.
EDIT: Added seen_table Procedure codes
DELIMITER $$
USE `xiroosco_mundoxiro`$$
DROP PROCEDURE IF EXISTS `seen_table`$$
CREATE DEFINER=`xiroosco`#`103.16.170.%` PROCEDURE `seen_table`(bound
VARCHAR(255),IN cmntId INT,IN cmntViewID VARCHAR(255),OUT viewCNT INT)
BEGIN
DECLARE seen_ID INT DEFAULT 0;
DECLARE seen_notifica_ID INT DEFAULT 0;
DECLARE seen_viewers TEXT;
DECLARE occurance INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE splitted_value INT;
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT seen.seen_ID, seen.seen_notifica_ID,
seen.seen_viewers
FROM seen
WHERE seen.seen_notifica_ID = cmntId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS seen2;
CREATE TEMPORARY TABLE seen2(
`seen_ID` INT NOT NULL,
`seen_notifica_ID` INT NOT NULL,
`seen_viewers` VARCHAR(255) NOT NULL
) ENGINE=MEMORY;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO seen_ID,seen_notifica_ID, seen_viewers;
IF done THEN
LEAVE read_loop;
END IF;
SET occurance = (SELECT LENGTH(seen_viewers) -
LENGTH(REPLACE(seen_viewers, bound, '')) +1);
SET i=1;
WHILE i <= occurance DO
SET splitted_value = (SELECT
REPLACE(SUBSTRING(SUBSTRING_INDEX(seen_viewers, bound, i),
LENGTH(SUBSTRING_INDEX(seen_viewers, bound, i - 1)) + 1), ',', ''));
INSERT INTO seen2 VALUES (seen_ID,seen_notifica_ID, splitted_value);
SET i = i + 1;
END WHILE;
END LOOP;
IF cmntViewID = "*" THEN
SELECT * FROM seen2 GROUP BY seen2.seen_viewers;
SELECT COUNT(*) INTO viewCNT FROM seen2;
ELSE
SELECT * FROM seen2 WHERE seen2.seen_viewers = cmntViewID GROUP BY
seen2.seen_viewers;
SELECT seen_ID INTO viewCNT FROM seen2 WHERE seen2.seen_viewers =
cmntViewID GROUP BY seen2.seen_viewers;
END IF;
CLOSE cur1;
END$$
DELIMITER ;
this is how i call my procedure example
CALL seen_table (',',2995,'356',#count);
NULL counts as one, but as far as I can see it is against the ANSI standard: If there are not results, there should also be no NULL returned.
To get a row count returned from a procedure (or any result set) in MySQL, there are information functions.
I do not know which select you want to return the count, so just giving you an example:
{your procedure before this part}
IF cmntViewID = "*" THEN
SELECT SQL_CALC_FOUND_ROWS * FROM seen2 GROUP BY seen2.seen_viewers;
SELECT COUNT(*) INTO viewCNT FROM seen2;
ELSE
SELECT * FROM seen2 WHERE seen2.seen_viewers = cmntViewID GROUP BY
seen2.seen_viewers;
SELECT seen_ID INTO viewCNT FROM seen2 WHERE seen2.seen_viewers =
cmntViewID GROUP BY seen2.seen_viewers;
END IF;
{your procedure after this part}
Then execute:
CALL seen_table();
SELECT FOUND_ROWS();
That will return the number of rows in the "SELECT SQL_CALC_FOUND_ROWS * FROM seen2 GROUP BY seen2.seen_viewers;" query.
So, I built this query in SQLYog, and it returned the results I was looking for. However, when I copy-pasted it into php and used mysqli to run each query / fetch the results, my results were different (namely, one field was null rather than the correct results).
Query:
SET SESSION group_concat_max_len = 1000000;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN field_number = ''',
wp.field_number,
'''
THEN ',
IF(lng.value = NULL, 'wp.value', 'lng.value'),
' ELSE NULL END) AS ',
CONCAT(fm.field_name, IF(fm.rank <> 0, fm.rank, ''))
)
)INTO #sql
FROM wp_rg_lead_detail wp
JOIN vh_rg_form_map fm
ON fm.field_number = wp.field_number
AND fm.form_id = wp.form_id
LEFT JOIN wp_rg_lead_detail_long lng
ON wp.id = lng.lead_detail_id
WHERE wp.form_id = 1;
SET #sql = CONCAT('SELECT lead_id,', #sql, ' FROM wp_rg_lead_detail wp
LEFT JOIN wp_rg_lead_detail_long lng
ON wp.id = lng.lead_detail_id
WHERE form_id = 1 GROUP BY lead_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
My results are almost exactly the same, the only difference lies in the picture field. Here are some pictures of the difference.
Silly mistake on my part: I had to add in a section to the where clause to ensure that I was getting a single lead_id (where lead_id = $n). I'm still unsure as to exactly why I was getting different responses for the same query in php and yog, but fixing my query fixed the problem.