I am writing a PL/SQL Procedure on SQL Developer, and I am running the below query :
EXECUTE IMMEDIATE 'select count(*) from '||var_Table||' into var_NumRec where COMPANY = '||var_company||' order by COMPANY';
OR
EXECUTE IMMEDIATE 'select count(*) from '||var_Table||' into '||var_NumRec||' where COMPANY = '||var_company||' order by COMPANY';
I am getting error "SQL command not properly ended"
The below query is working fine, but I have to add the "where" clause to this query:
select count(*) from '||var_Table into var_NumRec;
I have checked the procedure and running below code , which is working fine.
DECLARE
var_NumRec NUMBER(15);
var_Table VARCHAR2(40);
var_company VARCHAR2(25) := 'ABC';
TYPE
my_nested_table
IS TABLE OF VARCHAR2(40);
var_Direct my_nested_table := my_nested_table ('Employee', 'Accounts', 'FEE');
BEGIN
FOR i IN 1.. var_direct.count
LOOP
EXECUTE IMMEDIATE 'select count(*) from '||var_Direct(1) ||' where 1=1' into var_NumRec ;
DBMS_OUTPUT.PUT_LINE('ABC : '||var_NumRec);
END LOOP;
END;
You are using identifier "Company" which is invalid here, so earlier code was not running.
Use below query in place of your execute immediate in pl SQL procedure :
EXECUTE IMMEDIATE 'select count(*) from '||var_Table||' where COMPANY = '||var_company order by COMPANY
into var_NumRec;
When we use Execute immediate, we should put INTO outside the statement..
Hope this will work for you.
Related
I have this MySQL procedure:
CREATE PROCEDURE Employee_Dilligence(IN No_Hours INT)
BEGIN
SELECT EmpName,employees.EmpID, Hours_Worked,
Dilligence(Hours_Worked/(TIMESTAMPDIFF(Day, StartDate, CURDATE())*No_Hours))
AS concat('Worked more than', No_Hours, 'Hours')
FROM company.employees INNER JOIN company.employee_project INNER JOIN company.projects
ON employees.EmpID = employee_project.EmpID AND employee_project.ProjID = projects.ProjID
WHERE projects.ProjID = ProjectID;
And it works correctly, except for one thing: the concat here:
AS concat('Worked more than', No_Hours, 'Hours')
I do not understand why, though. The error message I'm getting is:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near '('Worked more than', No_Hours, 'hours per day')
FROM company.employees INNER JOIN c' at line 5
Yet it looks like I am using concat correctly, so how can I fix this problem? If I replace the problematic line with just:
AS N_Hours_Worked_Per_Day
then it works fine, but isn't as nice.
The expected output I want would look something like this:
Employee_Dilligence(2)
#COLUMN NAMES OF OUTPUT:
EmpName | EmpID | Hours_Worked | Worked more than 2 hours per day
Employee_Dilligence(3)
#COLUMN NAMES OF OUTPUT:
EmpName | EmpID | Hours_Worked | Worked more than 3 hours per day
You can't use CONCAT as an alias for a field in MySQL. The alias must be a string, this will be the field's name in your result.
To build an SQL that include a variable as a fieldname, you can use a prepared statement with the following:
DELIMITER $$
CREATE PROCEDURE Employee_Dilligence(IN No_Hours INT)
BEGIN
SET #sql = CONCAT('SELECT EmpName,employees.EmpID, Hours_Worked, Dilligence(Hours_Worked/(TIMESTAMPDIFF(Day, StartDate, CURDATE())*',No_Hours,')) AS "Worked more than', No_Hours, 'Hours" FROM company.employees INNER JOIN company.employee_project INNER JOIN company.projects ON employees.EmpID = employee_project.EmpID AND employee_project.ProjID = projects.ProjID WHERE projects.ProjID = ProjectID;');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
With this you first make your query as a string, then make a prepared statement from it, which can be executed by the server.
It seems you are doing a syntax error. please see blow how to use concate in query.
SELECT CONCAT(first_name, ' ', last_name) AS 'Name', dept FROM users;
I have a Users table and I'm getting user details (usual way) with id.
This is how I'm getting user details;
select id,kullaniciadi,FotoGet(K.Foto,K.Gender) from kullanicilar K where id=1;
FotoGet function always returning string value like 'Photos/ssss.jpg'
So far I have not trouble to use this way but I'm wondering how can I do this with a single function?
Like
set #uid=1;
Select UserGet(#uid);
I will put the id inside parentheses and the function will run my select query and return all user detail columns. id, kullaniciadi, FotoGet(K.id,K.Foto,K.Gender)
Can I use this way to get details?
A MySQL stored function cannot return multiple columns, it can only return a single scalar value.
But you could design a stored procedure that returns a result set:
CREATE PROCEDURE UserGet(uid INT)
SELECT id, kullaniciadi, FotoGet(K.Foto,K.Gender) FROM kullanicilar K WHERE id=uid;
Then call it like so:
CALL UserGet(1234);
It returns a result set just like a SELECT query would.
DELIMITER //
CREATE PROCEDURE UserGet(IN uid INT, IN column_name VARCHAR(64))
BEGIN
SET #sql = CONCAT('SELECT id, ', column_name, ' FROM kullanicilar K WHERE id=?');
PREPARE stmt FROM #sql;
SET #uid = uid;
EXECUTE stmt USING #uid;
END//
DELIMITER ;
Call it like so:
CALL UserGet(1234, 'kullaniciadi');
Remember that it's your responsibility to write code to pass a valid column name as the procedure argument. If you allow untrustworthy content to be passed, then it might be an SQL injection vulnerability.
Re your additional comment:
This should work fine:
CALL UserGet(1234, 'FotoGet(Foto,Gender)');
I've got MySQL procedure which I execute in MySQL Workbench. The problem is that it generates many new result-set, and GUI client show it (...many times) -
I found solution, which I can use instead just select clause to avoid generating result-sets. It looks like:
SELECT EXISTS(
SELECT ...
)
INTO #resultNm
Unfortunately it won't work with LIMIT ?,1 where ? is my variable 'i'. I also cant use just 'i' instead % because I am working on MySQL 5.1 (and limit clauses can't be done in other way). So my question - are other possibilities to hide result-sets?
CREATE PROCEDURE LOOPDOSSIERS(starter integer, finish integer)
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE row_oid binary(16);
DECLARE row_str VARCHAR(256);
DECLARE row_old VARCHAR(256);
SET i=starter;
WHILE i<finish DO
-- SET row_str = ();
SET #row_str = 'select CAST(concat(d.prefixe_numero,d.numero) as CHAR) from courrier_concerne_dossier as x
join dossier as d on
d.oid = x.dossier_oid limit ?,1';
PREPARE stmt1 FROM #row_str;
EXECUTE stmt1 USING #i;
SET #row_oid = 'select x.courrier_oid
from courrier_concerne_dossier as x
join dossier as d on
d.oid = x.dossier_oid LIMIT ?,1';
PREPARE stmt2 FROM #row_oid;
EXECUTE stmt2 USING #i;
select dossiers_str from courrier_envoye where oid = row_oid into row_old;
update courrier_envoye set dossiers_str = CAST(CONCAT(row_str, " ", row_old) AS CHAR) where oid = row_oid;
SET i = i + 1;
END WHILE;
End;
;;
LIMIT without an ORDER BY clause doesn't have a well defined behavior. For your parameters to work in a sensible way, you'll need to order by something. The starter and finish variables aren't very meaningful at the moment, but it's currently not clear what they're intended to be.
I think you can probably accomplish this whole procedure in a single query using the syntax in this answer (also probably much faster). That probably won't work with LIMIT, but I'd highly recommend using a range of some kind in the where clause rather than a limit anyway.
I'm trying to use a prepared statement in mysql workbench in a cursor. The cursor works on a very big data set so it is executed many times. Every time a new result is shown for the EXECUTE step. This results eventually in mysql workbench crashing because of too many open result windows.
In the cursor I do something like this:
PREPARE stmt2 FROM #eveningQuery;
EXECUTE stmt2;
DEALLOCATE PREPARE stmt2;
Normally I use stuff like
set aVar = (EXECUTE stmt2);
to silence the query but EXECUTE doesn't work like that.
Does anybody know how you can disable the output for the EXECUTE command in mysql?
Note: I understand how i can retrieve the data in a variable, however what I want to prevent is that it is displayed in the results overview like this
This will make mysql-workbench crash when looped too much.
edit because it was asked an example of the #eveningQuery.
SET #eveningQuery = CONCAT('select #resultNm := exists (select idSplitBill from tb_SplitDay where idSplitBill =', idSplitBillVar, ' and ', #columnNameEv ,' = 1 and softdelete = 0)');
idSplitBillVar = the id coming from the cursor.
#columnNameEv = a column that i am filling in variably.
I added this info because it was asked, however it doesn't really matter in my opinion because the question still stands even with the most simple query. When you execute a prepared statement, you will get a output result. I just want to disable this behaviour.
The query you use creates new result-set, and GUI client show it (...many times) -
SELECT #resultNm:=EXISTS(
SELECT idSplitBill FROM tb_SplitDay
WHERE idSplitBill =', idSplitBillVar, ' AND ', #columnNameEv ,' = 1 AND softdelete = 0
)
You can rewrite this query, and result-set won't be created -
SELECT EXISTS(
SELECT idSplitBill FROM tb_SplitDay
WHERE idSplitBill =', idSplitBillVar, ' AND ', #columnNameEv ,' = 1 AND softdelete = 0
)
INTO #resultNm
I am writing a stored procedure where I have an input parameter called my_size that is an INTEGER. I want to be able to use it in a LIMIT clause in a SELECT statement. Apparently this is not supported, is there a way to work around this?
# I want something like:
SELECT * FROM some_table LIMIT my_size;
# Instead of hardcoding a permanent limit:
SELECT * FROM some_table LIMIT 100;
For those, who cannot use MySQL 5.5.6+ and don't want to write a stored procedure, there is another variant. We can add where clause on a subselect with ROWNUM.
SET #limit = 10;
SELECT * FROM (
SELECT instances.*,
#rownum := #rownum + 1 AS rank
FROM instances,
(SELECT #rownum := 0) r
) d WHERE rank < #limit;
STORED PROCEDURE
DELIMITER $
CREATE PROCEDURE get_users(page_from INT, page_size INT)
BEGIN
SET #_page_from = page_from;
SET #_page_size = page_size;
PREPARE stmt FROM "select u.user_id, u.firstname, u.lastname from users u limit ?, ?;";
EXECUTE stmt USING #_page_from, #_page_size;
DEALLOCATE PREPARE stmt;
END$
DELIMITER ;
USAGE
In the following example it retrieves 10 records each time by providing start as 1 and 11. 1 and 11 could be your page number received as GET/POST parameter from pagination.
call get_users(1, 10);
call get_users(11, 10);
A search turned up this article. I've pasted the relevant text below.
Here's a forum post showing an example of prepared statements letting
you assign a variable value to the limit clause:
http://forums.mysql.com/read.php?98,126379,133966#msg-133966
However, I think this bug should get some attention because I can't
imagine that prepared statements within a procedure will allow for any
procedure-compile-time optimizations. I have a feeling that prepared
statements are compiled and executed at the runtime of the procedure,
which probaby has a negative impact on efficiency. If the limit
clause could accept normal procedure variables (say, a procedure
argument), then the database could still perform compile-time
optimizations on the rest of the query, within the procedure. This
would likely yield faster execution of the procedure. I'm no expert
though.
I know this answer has come late, but try SQL_SELECT_LIMIT.
Example:
Declare rowCount int;
Set rowCount = 100;
Set SQL_SELECT_LIMIT = rowCount;
Select blah blah
Set SQL_SELECT_LIMIT = Default;
This feature has been added to MySQL 5.5.6.
Check this link out.
I've upgraded to MySQL 5.5 just for this feature and works great.
5.5 also has a lot of performance upgrades in place and I totally recommend it.
Another way, the same as wrote "Pradeep Sanjaya", but using CONCAT:
CREATE PROCEDURE `some_func`(startIndex INT, countNum INT)
READS SQL DATA
COMMENT 'example'
BEGIN
SET #asd = CONCAT('SELECT `id` FROM `table` LIMIT ',startIndex,',',countNum);
PREPARE zxc FROM #asd;
EXECUTE zxc;
END;
As of MySQL version 5.5.6, you can specify LIMIT and OFFSET with variables / parameters.
For reference, see the 5.5 Manual, the 5.6 Manual and #Quassnoi's answer
I've faced the same problem using MySql 5.0 and wrote a procedure with the help of #ENargit's answer:
CREATE PROCEDURE SOME_PROCEDURE_NAME(IN _length INT, IN _start INT)
BEGIN
SET _start = (SELECT COALESCE(_start, 0));
SET _length = (SELECT COALESCE(_length, 999999)); -- USING ~0 GIVES OUT OF RANGE ERROR
SET #row_num_personalized_variable = 0;
SELECT
*,
#row_num_personalized_variable AS records_total
FROM(
SELECT
*,
(#row_num_personalized_variable := #row_num_personalized_variable + 1) AS row_num
FROM some_table
) tb
WHERE row_num > _start AND row_num <= (_start + _length);
END;
Also included the total rows obtained by the query with records_total.
you must DECLARE a variable and after that set it. then the LIMIt will work and put it in a StoredProcedure not sure if it works in normal query
like this:
DECLARE rowsNr INT DEFAULT 0;
SET rowsNr = 15;
SELECT * FROM Table WHERE ... LIMIT rowsNr;