我在表格中有多条记录:
UserTable:
UID AGE Contact
22 61 8899778899
14 45 8877556644
16 75 7894561246
我想编写一个程序,它将接受UID列表并返回相应的联系号码。
Input output
<22,14,16> <(22,8899778899),(14,8877556644),(16,7894561246)>
我尝试过以下程序,
drop procedure if exists testWC;
CREATE PROCEDURE testWC(Array_String VARCHAR(100))
BEGIN
SELECT UID,Contact FROM UserTable
WHERE UID IN (Array_String);
END
call testWC('22,14,16');
Result:
UID Contact
22 8899778899
但它在列表中只占22,即字符串列表中的第一个元素。帮助我提出宝贵的建议。
答案 0 :(得分:1)
我不知道为什么它不起作用。我在类似的情况下使用预备语句,在这种情况下也适用。
CREATE PROCEDURE testWC(Array_String VARCHAR(100))
BEGIN
SET @stmt = CONCAT('SELECT UID, Contact FROM UserTable WHERE UID IN (', Array_String, ')');
PREPARE q FROM @stmt;
EXECUTE q;
DEALLOCATE PREPARE q;
END //
我允许您根据需要格式化结果。
答案 1 :(得分:1)
IN子句不接受此类查询,因为您实际提供的是值为'22,14,16'
的VARCHAR2参数。
最好的方法是将ARRAY类型参数传递给过程。
以下示例
CREATE TYPE NUMBER_10_ARRAY IS TABLE OF NUMBER(10);
CREATE TYPE T_UID_CONTACT IS RECORD (uid NUMBER, contact NUMBER);
CREATE TYPE T_UID_CONTACT_ARRAY IS TABLE OF T_UID_CONTACT;
CREATE OR REPLACE PROCEDURE testWS(p_uids NUMBER_10_ARRAY)
IS
lt_uid_contacts T_UID_CONTACT := NEW T_UID_CONTACT();
CURSOR c_fetch_uid_contacts IS
SELECT
uid
,contact
FROM
user_table
WHERE
uid IN ((SELECT column_value FROM TABLE(p_uids)));
BEGIN
OPEN c_fetch_uid_contacts;
FETCH c_fetch_uid_contacts BULK COLLECT INTO lt_uid_contacts;
CLOSE c_fetch_uid_contacts;
-- Now you have all the records in your lt_uid_contacts variable
END testWS;
您还可以撰写pipelined
function
,以便能够通过简单的查询检索结果。
CREATE OR REPLACE FUNCTION testWS(p_uids NUMBER_10_ARRAY) RETURN T_UID_CONTACT PIPELINED
IS
lt_uid_contacts T_UID_CONTACT := NEW T_UID_CONTACT();
CURSOR c_fetch_uid_contacts IS
SELECT
uid
,contact
FROM
user_table
WHERE
uid IN ((SELECT column_value FROM TABLE(p_uids)));
BEGIN
-- Fetch all rows at once (you switch PL/SQL - SQL context only once)
OPEN c_fetch_uid_contacts;
FETCH c_fetch_uid_contacts BULK COLLECT INTO lt_uid_contacts;
CLOSE c_fetch_uid_contacts;
-- If any rows had been fetched, pipe rows so the pipelined function could return them
IF lt_uid_contacts.COUNT > 0 THEN
FOR idx IN lt_uid_contacts.FIRST .. lt_uid_contacts.LAST
LOOP
PIPE ROW(lt_uid_contacts(idx));
END LOOP;
END IF;
RETURN;
-- Handle NO_DATA_NEEDE exception, fired only in PIPELINED function in case SELECT statement using this function
-- didn't need the entire set of rows (e.g. limited by the WHERE clause)
EXCEPTION
WHEN NO_DATA_NEEDED THEN
NULL; -- exception is ignored in this case, but generally, it is a terrible practice to ignore any exceptions like this
-- if anytime you didn't know what to do on exception, it's better not to handle that exception at all and let the error occur
END testWS;
-- Then you can just use a SELECT query
SELECT
uid
,contact
FROM
TABLE(
testWS(
p_uids => CAST(
MULTISET((SELECT DECODE(LEVEL,1,22,2,14,3,16) FROM dual CONNECT BY LEVEL < 4))
AS NUMBER_10_ARRAY
)
)
) tab;
但是如果你真的想要将参数保持为由逗号分隔值组成的VARCHAR2,你可以使用下面的查询:
WITH uids AS (
SELECT
REPLACE(REGEXP_SUBSTR(Array_String ,',?\d+,?',1,LEVEL),',','') AS the_id
FROM
text
CONNECT BY LEVEL <= REGEXP_COUNT(Array_String ,',')+1
)
SELECT
ut.uid
,ut.contact
FROM
user_table ut
,uids
WHERE
ut.uid = uids.the_id;