2017-04-26 106 views
0
  1. 有什麼方法可以在Oracle SQL的where子句中使用列數據類型?我的表包含具有不同數據類型的列,因此我只想使用'char'數據類型的列。如何在where子句中使用data_type

  2. 我需要檢查每列中是否至少有1個值設置爲'T'。有沒有更好的方法來檢查這個,比如果使用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,則用戶可以使用設置操作使用文件。有更多的數據類型,特權和列,這只是一個簡單的例子。

我想,沒有快速的方法來找到只有CHAR列,所以我不得不簡單地寫在Select的每一列。

+1

你會需要使用'立即執行'。 –

+1

這聽起來像一個非常奇怪的任務或一個非常糟糕的數據模型。通常人們確切地知道要使用哪些列。爲什麼我要從產品表中選擇所有行,其中一個char列等於'T'(所有「布爾」列包含true,我想呢?)?這樣的結果可能告訴我什麼(例如,所有有庫存或女性用品,或者對環境友好或者適合未成年人)?似乎沒有道理。除此之外,動態構建查詢,例如使用PL/SQL。 –

+0

我有一個表格,具有訪問某些操作的權限。每一行都包含與一種附件和列定義有關的一種類型的權限,可以對所選的一種進行哪種操作。 Appart來自具有真/假值的列,列中也有字符串,日期或數字值。我的任務是檢查哪些用戶擁有特權,可以使用附件。即有一個。PNG文件,用戶有用戶和管理員權限,我需要檢查他是否可以打開和刪除那種文件。 – micnow21

回答

1

Alex Poole有一個很好的評論 - 如果您已經知道哪些列包含T/F數據,則不需要按數據類型進行查詢,因爲您已經知道按名稱檢查哪些列。您可以按列名查詢。

我會提供一個答案,如果你做的話不是已經知道哪些列需要檢查,但也會包含遠低於靜態sql的示例。我不確定你的第二個要求到底是什麼意思,所以我會添加幾個不同角度的例子。正如Gordon Linoff在評論中提到的,這些將使用EXECUTE IMMEDIATE

這個第一個例子解釋了你的要求,你事先不知道表(否則你可以檢查它的CHAR列,並直接查詢),但要檢查是否至少有一行有一個T爲每個給出TABLECHAR列(跨行)。

該塊將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的列數,然後執行動態查詢來算多少列至少有一個排在每個CHART值和T列的計數與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'); 

,並再次運行:

All: 3 CHAR columns have at least one T value 

靜態SQL當量(如果你已經知道你的表/列)爲:

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 S其中至少一個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 

或可替換地得到單列已經在他們的CHAR列NO T值,通過切換從ANYALL

WHERE 1 = ANY 

WHERE 1 <> ALL 

給出一個行:

RowId: AAGKHPAFJAABL49AAA 

靜態eqivalent(如果你已經知道你的表,並不需要使用的數據類型)是:

SELECT ROWID 
FROM HETEROGENEOUS 
WHERE 1 = ANY (DECODE(TRIM(CHAR_COL_1), 'T', 1, 0), 
       DECODE(TRIM(CHAR_COL_2), 'T', 1, 0), 
       DECODE(TRIM(CHAR_COL_3), 'T', 1, 0));​ 
+0

謝謝你的回答,請看看我的編輯。 – micnow21

+0

謝謝@ micnow21我會查看更新並跟進 – alexgibbs

+0

@ micnow21您的更新有助於澄清事情;感謝您的更新。既然你已經知道表和列,通常最好使用帶有列名的靜態sql。 Oracle不支持按數據類型選擇/過濾。如果您想通過數據類型動態執行sql,則需要使用pl/sql,不過在更新中,它看起來像是在行之間查詢,而不是在表/行級別查詢。在第二個問題中,所有需要'MAX'來檢查權限。如果您想要一個可以簡化查詢的示例或其他數據模型,請告訴我。謝謝 – alexgibbs