如何在where

时间:2017-04-26 12:28:56

标签: sql oracle

  1. 有没有办法在Oracle SQL的where子句中使用列数据类型?我的表包含具有不同数据类型的列,因此,我希望只有“char”数据类型的列。

  2. 我需要检查每列中至少有1个值是否设置为“T”。有没有更好的方法来检查这个,而不是使用if statment?

  3. 感谢您的帮助。

    修改

    更具体地说,我添加了简单的表来表示问题。

    此外,正如我所说,还有更多列,包括一些日期列。比方说,该用户同时拥有

    +----------+------------+------+------+--------+----------+--------+
    | 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中编写每一列。

1 个答案:

答案 0 :(得分:1)

Alex Poole有一个很好的评论 - 如果您已经知道哪些列包含T/F数据,则无需按数据类型进行查询,因为您已经知道要按名称检查哪些列。您只需按列名查询即可。

我会提供一个答案,以防你已经知道需要检查哪些列,​​但也包括远低于静态sql的示例。我不确定你的第二个要求是什么意思,所以我将添加几个不同角度的例子。这些将使用EXECUTE IMMEDIATE,正如Gordon Linoff在评论中提到的那样。

第一个示例解释了您事先不了解表格的要求(否则您只需检查其CHAR列并直接查询),但要检查至少一行是否有对于给定TTABLE列(跨行)中的每一列,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