MySQL procedure error in dynamic column name using EXEC () - mysql-workbench

I am getting an error in MySQL procedure at EXEC () function:
What is the cause of error?
CREATE PROCEDURE get_string_try(in_strlen int, in_id int)
BEGIN
set #var:='';
while(in_strlen>0)
do
set #var:=concat(#var,IFNULL(ELT(1+FLOOR(RAND() * 53), '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',' ','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'),'kovendan'));
set in_strlen:=in_strlen-1;
set #ix :=1;
while (#ix < 4)
do
set #select_column_insert:= ELT(#ix, 'address','lastname','middlename');
#SET #DynamicQuery_1 = ('UPDATE students set ' + #select_column_insert +' = '+ #var +' where id = '+in_id);
#SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = Database() AND TABLE_NAME = 'students' AND column_name = 'middlename' INTO #select_column_insert;
EXEC('UPDATE students set ' + #select_column_insert +' = '+ #var +' where id = '+in_id);
set #ix = #ix+1;
end while;
end while;
END $$
delimiter ;
CALL get_string_try(6,7);

And finally found the solution.
refer below:
DELIMITER $$
CREATE PROCEDURE get_string_try(in_strlen int, in_id int)
BEGIN
set #var:='';
while(in_strlen>0)
do
set #var:=concat(#var,IFNULL(ELT(1+FLOOR(RAND() * 53), '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',' ','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'),'kovendan'));
set in_strlen:=in_strlen-1;
set #ix :=1;
while (#ix < 4)
do
set #select_column_insert:= ELT(#ix, 'address','lastname','middlename');
SET #DynamicQuery_1 = CONCAT('UPDATE students set ', #select_column_insert, '= ', "'", #var,"'" ,' where id = ',in_id);
PREPARE stmt FROM #DynamicQuery_1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
set #ix = #ix+1;
end while;
end while;
END $$
delimiter ;
CALL get_string_try(6,8);

Related

BigQuery - How to use 'call <stored.procedure>' or output of a procedure in a Select, Insert, With statement

Want to do something like this:
Create Function dataset.sp_1(v_table STRING, v_ymd DATE) as (
BEGIN
DECLARE v_select, v_columns, v_dl_table, v_sbx_table, v_filter STRING;
Case v_table
WHEN "tab1" THEN
SET v_dl_table = 'dl_dataset.tab1';
SET v_sbx_table = 'sbx_dataset.tab1';
SET v_columns = 'Timestamp, col1, col2, col3';
SET v_filter = 'AND ColId IS NOT NULL';
End CASE
);
Set v_select = 'SELECT ' || v_columns || ' FROM ' || v_sbx_table|| ' WHERE DATE(Timestamp) = "' || v_ymd || '" ' || v_filter;
EXECUTE IMMEDIATE v_select;
END;
call dataset.sp_1("tab1","2022-01-05"); ---- Works fine.
=-=--= How to make this work=-=-=
Select * from (call dataset.sp_1("tab1","2022-01-05"));
OR
WITH
C as (call dataset.sp_1("tab1","2022-01-05"))
select * from C;
=-=-=-=-=

How to use a Function Parameter in a Cursor that's incorporated with Dynamic SQL in Postgres Functions?

Created this Postgres Function which is working fine, but the actual requirement is to pass the input parameter in the function to the Cursor which uses the dynamic SQL as follows,
The below is the Function
CREATE OR REPLACE FUNCTION ssp2_pcat.find_shift_dates (date_to_find date)
RETURNS void
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
DECLARE
C1 CURSOR FOR
SELECT TABLE_NAME, 'SELECT COUNT(*) FROM ' || TABLE_NAME || ' WHERE ' ||
COLUMN_NAME || ' = '||
'CASE WHEN ' || COLUMN_NAME || ' LIKE ' || '''%START%'''||' THEN
date_to_find ELSE date_to_find-1 END;' SQL_TEXT
FROM (
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME IN (SELECT TABLE_NAME FROM RESET_DATES WHERE RESET_IT =
'Y') AND
UPPER(DATA_TYPE) = 'DATE'
AND (COLUMN_NAME LIKE '%START%' OR COLUMN_NAME LIKE '%END%')
AND (COLUMN_NAME NOT LIKE '%TEST%'
AND COLUMN_NAME NOT LIKE '%PCAT%'
AND COLUMN_NAME NOT LIKE '%ORDER%'
AND COLUMN_NAME NOT LIKE '%SEASON%'
AND COLUMN_NAME NOT LIKE '%_AT')
ORDER BY 1, 2) A;
END_COUNT INTEGER := 0;
START_COUNT INTEGER := 0;
TABLENAME VARCHAR(32) := 'ALFU';
l_start TIMESTAMP;
l_end TIMESTAMP;
Time_Taken VARCHAR(20);
BEGIN
l_start := clock_timestamp();
DELETE FROM SHIFT_DATES_COUNT;
FOR I IN C1 LOOP
IF I.TABLE_NAME <> TABLENAME THEN
INSERT INTO SHIFT_DATES_COUNT VALUES (TABLENAME, START_COUNT,
END_COUNT, current_timestamp::timestamp(0));
TABLENAME := I.TABLE_NAME;
END_COUNT := 0;
START_COUNT := 0;
END IF;
IF STRPOS(I.SQL_TEXT, 'END') > 0 THEN
EXECUTE I.SQL_TEXT INTO END_COUNT;
RAISE NOTICE '% ', ('END: ' || I.SQL_TEXT);
ELSE
EXECUTE I.SQL_TEXT INTO START_COUNT;
RAISE NOTICE '% ', ('START: ' || I.SQL_TEXT);
END IF;
END LOOP;
INSERT INTO SHIFT_DATES_COUNT VALUES (TABLENAME, START_COUNT, END_COUNT,
current_timestamp::timestamp(0));
RAISE NOTICE '% ', ('INSERT INTO SHIFT_DATES_COUNT Done...');
l_end := clock_timestamp();
Time_Taken := (l_end-l_start);
RAISE NOTICE '% ', ('FIND_SHIFT_DATES Took: ' || Time_Taken );
END;
$BODY$;
Please let me know how can I use the date_to_find input parameter in the Dynamic SQL in the Cursor in the above Function.
You can use unbound cursor, clause fetch to get data from cursor, and exit when not found to finish, like:
CREATE OR REPLACE FUNCTION example (p_name text) RETURNS void LANGUAGE 'plpgsql' AS $$
DECLARE
C1 refcursor;
res record;
BEGIN
OPEN c1 FOR EXECUTE 'SELECT * FROM pg_database WHERE datname like ''%'||p_name||'%''';
LOOP
FETCH c1 INTO res;
EXIT WHEN not found;
raise notice 'value datname: %',res.datname;
END LOOP;
CLOSE c1;
RETURN;
END; $$;
--in my case
select example ('test')
NOTICE: value datname: test
NOTICE: value datname: test_msmov
NOTICE: value datname: test_resources
NOTICE: value datname: test_load_table
NOTICE: value datname: test_resources2
Total query runtime: 63 msec
1 row retrieved.
You can use EXECUTE clause for open cursor, see the documentation of PostgreSQL
https://www.postgresql.org/docs/10/plpgsql-cursors.html#PLPGSQL-CURSOR-OPENING
Example:
OPEN curs1 FOR EXECUTE format('SELECT * FROM %I WHERE col1 = $1',tabname) USING keyvalue;

Getting Error With GROUP BY when Converting Query to Dynamic SQL

I'm trying to convert the following query to dynamic SQL to allow for variations:
UPDATE T
SET SumCount = J.SUM
FROM #temp T
JOIN (SELECT Count_99221 + COUNT_99222 + Count_99223 [SUM], t2.userID
FROM #temp t2
GROUP BY t2.userID, Count_99221 + COUNT_99222 + Count_99223
) J ON T.userID = J.UserID
This is what I have for the Dynamic SQL:
DECLARE #sql3 nvarchar(2000) =
'UPDATE T ' +
'SET SumCount = J.SumOfColumns ' +
'FROM #temp T ' +
'JOIN (SELECT ' + #columnSumString + ' [SumOfColumns], t2.userID ' +
'FROM #temp t2 ' +
'GROUP BY t2.userID, ' + #columnSumString +
' ) J ON T.userID = J.UserID'
EXEC sp_executesql #sql3
I am receiving the following error only when I run the query as Dynamic SQL:
Each GROUP BY expression must contain at least one column that is not
an outer reference.
Can somebody help explain why this is happening? I am new to Dynamic SQL so I'm not privy to any limitations for running queries this way.
Thank you in advance.
EDIT:
The variable #columnString is a string made by concatenating several other column names, created in the following way:
DECLARE #Cursor Cursor
DECLARE #code varchar(20)
DECLARE #ID INT
SET #cptCursor = CURSOR FOR
SELECT * FROM dbo.Split(#UserInput,CHAR(44))
OPEN #cptCursor
FETCH NEXT FROM #cptCursor INTO #ID, #code
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #colName varchar(50) = 'Count_' + cast(#code as varchar(10))
DECLARE #sql nvarchar(50) = 'ALTER TABLE #temp ADD ' + #colName + ' int'
EXEC sp_executesql #sql
--Code that adds values to each column that is created.....
SET #columnSumString = #colName + ' + ' + #columnSumString
--SET #columnSumString = #code + ' + ' + #columnSumString
FETCH NEXT FROM #cptCursor INTO #ID, #code
END
CLOSE #Cursor
DEALLOCATE #Cursor
SET #columnSumString = SUBSTRING(#columnSumString,1,LEN(#columnSumString)-2)
SELECT #columnSumString
The user input is a comma separated string. "Count_99221 + COUNT_99222 + Count_99223" is just one example of columns created from the user input "99221, 99222, 99223".
I also realized I was concatenating the #code variable into #columnSumString instead of #colName. Now when I run the query I don't get the error (even though I don't understand how the above error message relates to that mistake) but every value of SumCount is NULL.
IMHO you must re-write your query as follow:
UPDATE #temp
SET SumCount =
(SELECT Count_99221 + COUNT_99222 + Count_99223
FROM #temp t2
WHERE t2.userID = #temp.userID)
So the dynamic SQL will become:
DECLARE #columnString varchar(200)
SET #columnString = Count_99221 + COUNT_99222 + Count_99223
DECLARE #sql3 nvarchar(2000) =
N'UPDATE #temp ' +
'SET SumCount = (SELECT ' + #columnString +
' FROM #temp t2 WHERE t2.userID = #temp.userID)'
EXEC sp_executesql #sql3

Error with Query SELECT in cursor

I have problem with my select in cursor. Select works normal in other windows but I got error in procedure with cursor why ?
I change name of Tabele and Database but Select is OK outside this procedure
My error:
PL/SQL: ORA-04052:
ORA-00604:
ORA-03106:
CREATE OR REPLACE PROCEDURE ChangeDismissDate
IS
BEGIN
DECLARE
v_id VARCHAR2(40);
v_dateABC DATE;
v_dateDismiss DATE;
CURSOR cur IS
select emp.EMP_NO, abc.date, emp.DISMISS_DATE
from bazaabc.EmployeesDetails#BAZA_ABC abc,
employee_tab emp,
person_info_tab pin,
oracle_account oa
where bhd.emp_no = emp.EMP_NO
and pin.PERSON_ID = emp.EMP_NO
and oa.USERNAME = pin.USER_ID
and emp.EMP_NO in (
select pi.PERSON_ID from tab_person pi
where fu.active = 'TRUE'
and fu.IDENTITY = pi.USER_ID) AND emp.EMP_NO like '%L%'
and nvl(abc.date,to_date('20491231','yyyymmdd')) <> nvl(emp.DISMISS_DATE,to_date('20491231','yyyymmdd'));
BEGIN
OPEN cur;
LOOP
FETCH cur INTO v_id,v_dateABC,v_dateDismiss;
DBMS_OUTPUT.PUT_LINE('v_id: ' || v_id);
DBMS_OUTPUT.PUT_LINE('v_dateABC: ' || v_dateABC);
DBMS_OUTPUT.PUT_LINE('v_dateDismiss: ' ||v_dateDismiss );
EXIT WHEN cur%NOTFOUND;
END LOOP;
CLOSE cur;
END;
END;
/
Can you try with what errors you are getting by adding exception block
CREATE OR REPLACE PROCEDURE ChangeDismissDate
IS
BEGIN
DECLARE
v_id VARCHAR2(40);
v_dateABC DATE;
v_dateDismiss DATE;
CURSOR cur IS
select emp.EMP_NO, abc.date, emp.DISMISS_DATE
from bazaabc.EmployeesDetails#BAZA_ABC abc,
employee_tab emp,
person_info_tab pin,
oracle_account oa
where bhd.emp_no = emp.EMP_NO
and pin.PERSON_ID = emp.EMP_NO
and oa.USERNAME = pin.USER_ID
and emp.EMP_NO in (
select pi.PERSON_ID from tab_person pi
where fu.active = 'TRUE'
and fu.IDENTITY = pi.USER_ID)
AND emp.EMP_NO like '%L%'
and nvl(abc.date,to_date('20491231','yyyymmdd')) <>
nvl(emp.DISMISS_DATE,to_date('20491231','yyyymmdd'));
BEGIN
OPEN cur;
LOOP
FETCH cur INTO v_id,v_dateABC,v_dateDismiss;
DBMS_OUTPUT.PUT_LINE('v_id: ' || v_id);
DBMS_OUTPUT.PUT_LINE('v_dateABC: ' || v_dateABC);
DBMS_OUTPUT.PUT_LINE('v_dateDismiss: ' ||v_dateDismiss );
EXIT WHEN cur%NOTFOUND;
END LOOP;
CLOSE cur;
END;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
END;
/

T-SQL How To Count Of Records For Each Column

I have a table with over 120 columns and need to determine which column is used the least. I tried using sql queries to do this, but found T-SQL a bit simpler.
I tried the following but my count comes out as 0 for every column.
Declare data1 Cursor for select column_name
from information_schema.columns
where table_name = 'repository'
Declare #mField nvarchar(255)
Declare #count int
Open data1;
fetch next from data1 into #mField;
set #count = -1;
while ##fetch_status = 0
begin
select #count = count(#mField)
from repository where tablereference =
'central' and ( #mField!= null )
print #mField+' ' ;
print #count;
Fetch next from data1 into #mField;
end
close data1;
deallocate data1;
You can't count values like this because you are only testing if #mField is NULL. The column name isn't substituted.
COUNT ignores NULLs anyway so if you want to count non-null values, do this:
DECLARE #sql varchar(4000)
SET #sql = 'SELECT COUNT(*) AS Total '
SELECT #sql = #sql + ', COUNT(' + QUOTENAME(column_name) + ') AS ' + QUOTENAME(column_name)
from information_schema.columns
where table_name = 'repository'
SET #sql = #sql + ' FROM repository'
EXEC (#sql)
This queries the table once for all columns
You need to use some dynamic sql in the middle to acheive your aim here.
Declare data1 Cursor for select column_name
from information_schema.columns
where table_name = 'repository'
Declare #mField nvarchar(255)
Open data1;
fetch next from data1 into #mField;
while ##fetch_status = 0
begin
exec ('
declare #count int
select #count = count([' + #mField + '])
from repository where tablereference =
''central'' and ( [' + #mField + '] is not null)
if #count < 10
begin
print ''' + #mField + ' '' ;
print #count;
end
')
Fetch next from data1 into #mField;
end
close data1;
deallocate data1;
Your count(#mField) is a count of the litteral value that happens to be in #mField, its not resolving the field name into COUNT(fldBlah), you would need to use dynamic SQL for that.
Declare data1 Cursor FAST_FORWARD for select column_name
from information_schema.columns where table_name = 'repository'
Declare #mField nvarchar(255)
Declare #SQL varchar(1024)
Declare #results table (col_name varchar(128), non_nulls int)
Open data1;
fetch next from data1 into #mField;
while (##FETCH_STATUS = 0) begin
set #SQL = 'SELECT ''' + #mField + ''', count(' + #mField + ') from repository where tablereference = ''central'''
insert #results
exec(#SQL)
Fetch next from data1 into #mField;
end
close data1;
deallocate data1;
select * from #results
For an output like;
col_name non_nulls
[tablereference] 5
[another_col] 1
Where there are 5 non-null values in column tablereference etc
You need to use IS NOT NULL instead of != NULL