有没有办法在Oracle SQL的where子句中使用列数据类型?我的表包含具有不同数据类型的列,因此,我希望只有“char”数据类型的列。
我需要检查每列中至少有1个值是否设置为“T”。有没有更好的方法来检查这个,而不是使用if statment?
感谢您的帮助。
修改
更具体地说,我添加了简单的表来表示问题。
此外,正如我所说,还有更多列,包括一些日期列。比方说,该用户同时拥有
+----------+------------+------+------+--------+----------+--------+
| Datatype | Privileges | Open | Edit | Delete | Download | Upload |
+----------+------------+------+------+--------+----------+--------+
| PNG | Default | T | T | T | T | T |
| JPEG | Default | T | T | T | T | T |
| PDF | Default | T | F | F | T | T |
| DOCX | Default | T | T | F | T | T |
| PNG | Test | T | F | F | T | F |
| PDF | Test | T | F | F | T | F |
+----------+------------+------+------+--------+----------+--------+
此外,正如我所说,还有更多列,包括一些日期列。假设该用户具有这两种权限。我需要检查一下,用户可以访问哪种数据类型,以及他可以对每种数据类型执行哪些操作。即,由于PNG
权限,此用户可以使用Default
文件并执行各种操作。 Test
权限也可以在PNG
文件上提供一些操作,但不是每个操作都有。这就像我假设的位OR
操作。如果至少有一个设置为T
,则用户可以使用set操作处理文件。有更多的数据类型,权限和列,这只是一个简单的例子。
我想,没有快速找到CHAR
列的方法,因此我只需在Select
中编写每一列。
答案 0 :(得分:1)
Alex Poole有一个很好的评论 - 如果您已经知道哪些列包含T/F
数据,则无需按数据类型进行查询,因为您已经知道要按名称检查哪些列。您只需按列名查询即可。
我会提供一个答案,以防你不已经知道需要检查哪些列,但也包括远低于静态sql的示例。我不确定你的第二个要求是什么意思,所以我将添加几个不同角度的例子。这些将使用EXECUTE IMMEDIATE
,正如Gordon Linoff在评论中提到的那样。
第一个示例解释了您事先不了解表格的要求(否则您只需检查其CHAR
列并直接查询),但要检查至少一行是否有对于给定T
个TABLE
列(跨行)中的每一列,CHAR
。
该块将TABLE_NAME
作为参数,然后构建一个动态查询,检查每个COLUMN
是否在表中至少有一个值为T
的条目。
首先创建一个包含不同数据类型的测试表,包括一些CHAR
:
CREATE TABLE HETEROGENEOUS (
CHAR_COL_1 CHAR(10),
NUMBER_COL_1 NUMBER,
CHAR_COL_2 CHAR(10),
TIMESTAMP_COL_1 TIMESTAMP,
CHAR_COL_3 CHAR(10)
);
然后添加一些测试数据。第一次加载有三列中的两列,至少有一个T
值,因此测试失败。
INSERT INTO HETEROGENEOUS VALUES ('Chewbacca', 1, 'VOLTRON', SYSTIMESTAMP, 'Gundam');
INSERT INTO HETEROGENEOUS VALUES ('T', 1, 'Frodo', SYSTIMESTAMP, 'Starscream');
INSERT INTO HETEROGENEOUS VALUES ('X', 1, 'Bombadil', SYSTIMESTAMP, 'T');
然后运行块。此块计算CHAR
列的数量,然后执行动态查询以计算每个T
列中至少有一列具有CHAR
值的列数,并比较{的计数列数为T
列的{1}}列:
CHAR
结果:
DECLARE
V_TABLE_NAME VARCHAR2(128) := 'HETEROGENEOUS';
V_SQL_TEXT VARCHAR2(32000);
V_REQUIRED_COLUMN_COUNT NUMBER := 0;
V_OK_COLUMN_COUNT NUMBER := 0;
BEGIN
EXECUTE IMMEDIATE
UTL_LMS.FORMAT_MESSAGE('SELECT COUNT(*) FROM USER_TAB_COLUMNS WHERE TABLE_NAME = ''%s'' AND DATA_TYPE = ''CHAR''',V_TABLE_NAME)
INTO V_REQUIRED_COLUMN_COUNT;
SELECT 'SELECT ' ||LISTAGG('(SELECT COALESCE(MIN(1),0) FROM '||V_TABLE_NAME||' WHERE TRIM('||
COLUMN_NAME||') = ''T'' AND ROWNUM = 1)','+')
WITHIN GROUP (ORDER BY COLUMN_ID) || ' FROM DUAL'
INTO V_SQL_TEXT
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = V_TABLE_NAME
AND DATA_TYPE = 'CHAR' GROUP BY TABLE_NAME;
EXECUTE IMMEDIATE V_SQL_TEXT INTO V_OK_COLUMN_COUNT;
IF V_OK_COLUMN_COUNT < V_REQUIRED_COLUMN_COUNT
THEN
DBMS_OUTPUT.PUT_LINE(UTL_LMS.FORMAT_MESSAGE('Required at least: %s columns to have 1+ T values but only found: %s',TO_CHAR(V_REQUIRED_COLUMN_COUNT),TO_CHAR(V_OK_COLUMN_COUNT)));
ELSE
DBMS_OUTPUT.PUT_LINE(UTL_LMS.FORMAT_MESSAGE('All: %s CHAR columns have at least one T value',TO_CHAR(V_REQUIRED_COLUMN_COUNT)));
END IF;
END;
/
然后添加另一行以获取最后一个必需的Required at least: 3 columns to have 1+ T values but only found: 2
值:
T
然后又跑了:
INSERT INTO HETEROGENEOUS VALUES ('Deckard', 1, 'T', SYSTIMESTAMP, 'Megatron');
静态SQL等效项(如果您已经知道表/列)是:
All: 3 CHAR columns have at least one T value
如果您的要求是查找SELECT (SELECT COALESCE(MIN(1), 0) FROM HETEROGENEOUS
WHERE TRIM(CHAR_COL_1) = 'T' AND ROWNUM = 1) +
(SELECT COALESCE(MIN(1), 0) FROM HETEROGENEOUS
WHERE TRIM(CHAR_COL_2) = 'T' AND ROWNUM = 1) +
(SELECT COALESCE(MIN(1), 0) FROM HETEROGENEOUS
WHERE TRIM(CHAR_COL_3) = 'T' AND ROWNUM = 1)
FROM DUAL;
个,其中至少有一个ROW
列的值为CHAR
,则方法相同,但动态查询不同。
第二个示例将查找至少有一个T
列的值为CHAR
的所有行(并且只打印它们):
T
运行它会为任何DECLARE
V_TABLE_NAME VARCHAR2(128) := 'HETEROGENEOUS';
V_SQL_TEXT VARCHAR2(32000);
TYPE REFCURSOR IS REF CURSOR;
V_REFCURSOR REFCURSOR;
V_ROWID VARCHAR2(64);
BEGIN
SELECT 'SELECT ROWID FROM '||V_TABLE_NAME||' WHERE 1 = ANY ( '||LISTAGG('DECODE(TRIM('||COLUMN_NAME||'),''T'',1,0) ',',') WITHIN GROUP (ORDER BY COLUMN_ID)||')'
INTO V_SQL_TEXT
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = V_TABLE_NAME
AND DATA_TYPE = 'CHAR'
GROUP BY TABLE_NAME;
OPEN V_REFCURSOR FOR V_SQL_TEXT;
LOOP
FETCH V_REFCURSOR INTO V_ROWID;
EXIT WHEN V_REFCURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(UTL_LMS.FORMAT_MESSAGE('RowId: %s',V_ROWID));
END LOOP;
CLOSE V_REFCURSOR;
END;
/
列中的三行提供T:
CHAR
或者通过从RowId: AAGKHPAFJAABL49AAB
RowId: AAGKHPAFJAABL49AAC
RowId: AAGKHPAFJAABL49AAD
切换到T
来获取CHAR
列中没有ANY
值的单行:
ALL
给出一行:
WHERE 1 = ANY
WHERE 1 <> ALL
静态等效(如果您已经知道您的表并且不需要使用数据类型)是:
RowId: AAGKHPAFJAABL49AAA