需要从一个 table 中选择的列名来自另一个 table

Column Names that need to be selected from a table comes from another table

我有两个 table,table A 包含通用命名列中的数据。在其他 table B 中,我有一个 table A 的逗号分隔列名列表。

示例数据:

Table答:

+------+-----+-----+-----+-----+-----+------+-----+-----+-----+-----+-----+----+------+
| CODE | C1  | C2  | C3  | C4  | C5  |  C6  | C7  | M1  | M2  | M3  | M4  | M5 |  M6  |
+------+-----+-----+-----+-----+-----+------+-----+-----+-----+-----+-----+----+------+
| A1   | 102 | 275 | 400 | -55 |  -1 | 2779 |   5 | 157 | 236 | 332 | -94 |  7 | 2209 |
| A2   | 162 | 209 | 330 | -71 |  -4 | 1041 |   7 | 188 | 264 | 349 |  -3 | -8 | 3863 |
| A3   | 124 | 237 | 334 | -71 |   3 | 2086 |  24 | 126 | 299 | 366 | -36 | -8 | 1416 |
| A4   | 154 | 267 | 360 | -15 |   7 | 3900 |  24 | 103 | 260 | 316 | -92 |  2 | 3247 |
| A5   | 157 | 240 | 361 | -86 |   8 | 3871 | -13 | 123 | 296 | 380 | -80 | -6 | 3743 |
| A6   | 138 | 268 | 388 | -27 | -10 | 2939 | -23 | 181 | 229 | 393 | -46 | -6 | 1355 |
| A7   | 117 | 267 | 353 | -92 |  -6 | 3273 |  10 | 194 | 243 | 317 | -91 |  4 | 2508 |
| A8   | 138 | 207 | 343 | -67 |   3 | 1558 | -18 | 143 | 242 | 308 | -51 |  4 | 3955 |
| A9   | 175 | 225 | 359 | -11 |  -1 | 2344 |  13 | 174 | 229 | 380 |  -3 |  4 | 2611 |
| B1   | 137 | 295 | 364 | -48 |  -2 | 3827 |  24 | 169 | 257 | 304 | -58 |  9 | 1534 |
| B2   | 155 | 231 | 339 | -39 |  -1 | 2895 | -19 | 107 | 251 | 305 |  -1 |  2 | 2208 |
| B3   | 166 | 251 | 363 | -42 |  -2 | 1766 |   6 | 128 | 272 | 371 | -27 |  7 | 3460 |
| B4   | 116 | 200 | 317 | -72 |  -6 | 1073 | -13 | 160 | 230 | 307 | -73 | -8 | 3393 |
+------+-----+-----+-----+-----+-----+------+-----+-----+-----+-----+-----+----+------+

Table乙:

+------+-------------------+
| CODE |    SELECT_COLS    |
+------+-------------------+
| A1   | C1,C2,C3,M1,M2,M3 |
| A2   | C1,C2,C3,M1,M2,M3 |
| A3   | C1,C2,C3,M1,M2,M3 |
| A4   | C1,C2,C3,C4,M1    |
| A5   | C1,C2,C3,C4,C5,M1 |
| A6   | C1,C2,C3,M1,M2    |
| A7   | C1,C2,C3,C4,M1,M2 |
| A8   | C1,C2,C3,C4,M1,M2 |
| A9   | C1,C2,C3,C4,M1,M2 |
| B1   | C1,C2,C3,C4,M1    |
| B2   | C1,C2,C3,C4,M1    |
| B3   | C1,C2,M1          |
| B4   | C1,M1             |
+------+-------------------+

有什么方法可以 select 只有 table B 的 SELECT_COLS 列中指定的列来自 table A?

有办法吗?是的,动态 SQL。这是一个例子:

示例数据:

SQL> select * from a;

CO         C1         C2         C3         C4
-- ---------- ---------- ---------- ----------
A1        102        275        400        -55
A2        162        209        330        -71

SQL> select * from b;

CO SELECT_C
-- --------
A1 C1,C2,C3
A2 C2,C4

函数 returns refcursor:

SQL> create or replace function f_code (par_code in varchar2)
  2  return sys_refcursor
  3  is
  4    l_str   varchar2(200);
  5    l_rc    sys_refcursor;
  6  begin
  7    select 'select ' || b.select_cols || ' from a'
  8    into l_str
  9    from b
 10    where b.code = par_code;
 11    open l_rc for l_str;
 12    return l_rc;
 13  end;
 14  /

Function created.

测试:

SQL> var rc refcursor
SQL> exec :rc := f_code('A1');

PL/SQL procedure successfully completed.

SQL> print rc

        C1         C2         C3
---------- ---------- ----------
       102        275        400
       162        209        330

SQL>

这里的两个潜在解决方案都不需要动态 SQL 或使用 PL/SQL,它们将为您提供所需的 数据

Oracle 不支持从动态列中 selecting;是的,您可以使用 PL/SQL 来动态构建 SQL 语句,但是当该语句运行时,它将具有固定的列。此外,如果您有一组数据需要 C1,C2,C3,M1,M2,M3 而另一组数据需要 C1,C2,C3,C4,C5,M1 那么您是否需要 6 列数据(加上代码),如果需要,您如何知道这些列是什么包含?或者您想要 8 列数据(第一列 6 列,第二列额外 2 列),如果是,您怎么知道您不只是想要所有列;因此,仅获取每一列的数据并将不打算显示的值设置为 NULL 是不是更容易,然后您可以在应用程序中隐藏所有 NULL 的列等级。

因此,与其尝试获取动态列,不如 select 将它们作为行,然后如果您需要将它们转回列,请在您用于访问数据库的任何应用程序层中执行此操作。

SELECT a.*
FROM   (
         SELECT Code, Key, Value
         FROM   tableA
         UNPIVOT (
           VALUE FOR KEY IN (
             C1, C2, C3, C4, C5, C6, C7, M1, M2, M3, M3, M4, M5, M6
           )
         )
       ) a
       INNER JOIN (
         TableB
       ) B
       ON ( a.code = b.code AND INSTR( b.select_cols, a.key ) > 0 )

其中,对于您的示例数据:

CREATE TABLE tableA ( CODE, C1, C2, C3, C4, C5, C6, C7, M1, M2, M3, M4, M5, M6 ) AS
SELECT 'A1', 102, 275, 400, -55, -1, 2779, 5, 157, 236, 332, -94, 7, 2209 FROM DUAL UNION ALL
SELECT 'A2', 162, 209, 330, -71, -4, 1041, 7, 188, 264, 349, -3, -8, 3863 FROM DUAL UNION ALL
SELECT 'A3', 124, 237, 334, -71, 3, 2086, 24, 126, 299, 366, -36, -8, 1416 FROM DUAL UNION ALL
SELECT 'A4', 154, 267, 360, -15, 7, 3900, 24, 103, 260, 316, -92, 2, 3247 FROM DUAL UNION ALL
SELECT 'A5', 157, 240, 361, -86, 8, 3871, -13, 123, 296, 380, -80, -6, 3743 FROM DUAL UNION ALL
SELECT 'A6', 138, 268, 388, -27, -10, 2939, -23, 181, 229, 393, -46, -6, 1355 FROM DUAL UNION ALL
SELECT 'A7', 117, 267, 353, -92, -6, 3273, 10, 194, 243, 317, -91, 4, 2508 FROM DUAL UNION ALL
SELECT 'A8', 138, 207, 343, -67, 3, 1558, -18, 143, 242, 308, -51, 4, 3955 FROM DUAL UNION ALL
SELECT 'A9', 175, 225, 359, -11, -1, 2344, 13, 174, 229, 380, -3, 4, 2611 FROM DUAL UNION ALL
SELECT 'B1', 137, 295, 364, -48, -2, 3827, 24, 169, 257, 304, -58, 9, 1534 FROM DUAL UNION ALL
SELECT 'B2', 155, 231, 339, -39, -1, 2895, -19, 107, 251, 305, -1, 2, 2208 FROM DUAL UNION ALL
SELECT 'B3', 166, 251, 363, -42, -2, 1766, 6, 128, 272, 371, -27, 7, 3460 FROM DUAL UNION ALL
SELECT 'B4', 116, 200, 317, -72, -6, 1073, -13, 160, 230, 307, -73, -8, 3393 FROM DUAL;

CREATE TABLE tableB ( CODE, SELECT_COLS ) AS
SELECT 'A1', 'C1,C2,C3,M1,M2,M3' FROM DUAL UNION ALL
SELECT 'A2', 'C1,C2,C3,M1,M2,M3' FROM DUAL UNION ALL
SELECT 'A3', 'C1,C2,C3,M1,M2,M3' FROM DUAL UNION ALL
SELECT 'A4', 'C1,C2,C3,C4,M1' FROM DUAL UNION ALL
SELECT 'A5', 'C1,C2,C3,C4,C5,M1' FROM DUAL UNION ALL
SELECT 'A6', 'C1,C2,C3,M1,M2' FROM DUAL UNION ALL
SELECT 'A7', 'C1,C2,C3,C4,M1,M2' FROM DUAL UNION ALL
SELECT 'A8', 'C1,C2,C3,C4,M1,M2' FROM DUAL UNION ALL
SELECT 'A9', 'C1,C2,C3,C4,M1,M2' FROM DUAL UNION ALL
SELECT 'B1', 'C1,C2,C3,C4,M1' FROM DUAL UNION ALL
SELECT 'B2', 'C1,C2,C3,C4,M1' FROM DUAL UNION ALL
SELECT 'B3', 'C1,C2,M1' FROM DUAL UNION ALL
SELECT 'B4', 'C1,M1' FROM DUAL;

输出:

CODE | KEY | VALUE
:--- | :-- | ----:
A1   | C1  |   102
A1   | C2  |   275
A1   | C3  |   400
A1   | M1  |   157
A1   | M2  |   236
A1   | M3  |   332
A1   | M3  |   332
A2   | C1  |   162
A2   | C2  |   209
A2   | C3  |   330
A2   | M1  |   188
A2   | M2  |   264
A2   | M3  |   349
A2   | M3  |   349
A3   | C1  |   124
A3   | C2  |   237
A3   | C3  |   334
A3   | M1  |   126
A3   | M2  |   299
A3   | M3  |   366
A3   | M3  |   366
A4   | C1  |   154
A4   | C2  |   267
A4   | C3  |   360
A4   | C4  |   -15
A4   | M1  |   103
A5   | C1  |   157
A5   | C2  |   240
A5   | C3  |   361
A5   | C4  |   -86
A5   | C5  |     8
A5   | M1  |   123
A6   | C1  |   138
A6   | C2  |   268
A6   | C3  |   388
A6   | M1  |   181
A6   | M2  |   229
A7   | C1  |   117
A7   | C2  |   267
A7   | C3  |   353
A7   | C4  |   -92
A7   | M1  |   194
A7   | M2  |   243
A8   | C1  |   138
A8   | C2  |   207
A8   | C3  |   343
A8   | C4  |   -67
A8   | M1  |   143
A8   | M2  |   242
A9   | C1  |   175
A9   | C2  |   225
A9   | C3  |   359
A9   | C4  |   -11
A9   | M1  |   174
A9   | M2  |   229
B1   | C1  |   137
B1   | C2  |   295
B1   | C3  |   364
B1   | C4  |   -48
B1   | M1  |   169
B2   | C1  |   155
B2   | C2  |   231
B2   | C3  |   339
B2   | C4  |   -39
B2   | M1  |   107
B3   | C1  |   166
B3   | C2  |   251
B3   | M1  |   128
B4   | C1  |   116
B4   | M1  |   160

如果您可以拥有任何行并希望它们全部作为列,那么只需获取它们并将值设置为 NULL 如果它们不在 select_cols 列中:

SELECT a.code,
       CASE WHEN INSTR( b.select_cols, 'C1' ) > 0 THEN C1 END AS C1,
       CASE WHEN INSTR( b.select_cols, 'C2' ) > 0 THEN C2 END AS C2,
       CASE WHEN INSTR( b.select_cols, 'C3' ) > 0 THEN C3 END AS C3,
       CASE WHEN INSTR( b.select_cols, 'C4' ) > 0 THEN C4 END AS C4,
       CASE WHEN INSTR( b.select_cols, 'C5' ) > 0 THEN C5 END AS C5,
       CASE WHEN INSTR( b.select_cols, 'C6' ) > 0 THEN C6 END AS C6,
       CASE WHEN INSTR( b.select_cols, 'C7' ) > 0 THEN C7 END AS C7,
       CASE WHEN INSTR( b.select_cols, 'M1' ) > 0 THEN M1 END AS M1,
       CASE WHEN INSTR( b.select_cols, 'M2' ) > 0 THEN M2 END AS M2,
       CASE WHEN INSTR( b.select_cols, 'M3' ) > 0 THEN M3 END AS M3,
       CASE WHEN INSTR( b.select_cols, 'M4' ) > 0 THEN M4 END AS M4,
       CASE WHEN INSTR( b.select_cols, 'M5' ) > 0 THEN M5 END AS M5,
       CASE WHEN INSTR( b.select_cols, 'M6' ) > 0 THEN M6 END AS M6
FROM   tableA a
       INNER JOIN tableB b
       ON ( a.code = b.code )

输出:

CODE |  C1 |   C2 |   C3 |   C4 |   C5 |   C6 |   C7 |  M1 |   M2 |   M3 |   M4 |   M5 |   M6
:--- | --: | ---: | ---: | ---: | ---: | ---: | ---: | --: | ---: | ---: | ---: | ---: | ---:
A1   | 102 |  275 |  400 | null | null | null | null | 157 |  236 |  332 | null | null | null
A2   | 162 |  209 |  330 | null | null | null | null | 188 |  264 |  349 | null | null | null
A3   | 124 |  237 |  334 | null | null | null | null | 126 |  299 |  366 | null | null | null
A4   | 154 |  267 |  360 |  -15 | null | null | null | 103 | null | null | null | null | null
A5   | 157 |  240 |  361 |  -86 |    8 | null | null | 123 | null | null | null | null | null
A6   | 138 |  268 |  388 | null | null | null | null | 181 |  229 | null | null | null | null
A7   | 117 |  267 |  353 |  -92 | null | null | null | 194 |  243 | null | null | null | null
A8   | 138 |  207 |  343 |  -67 | null | null | null | 143 |  242 | null | null | null | null
A9   | 175 |  225 |  359 |  -11 | null | null | null | 174 |  229 | null | null | null | null
B1   | 137 |  295 |  364 |  -48 | null | null | null | 169 | null | null | null | null | null
B2   | 155 |  231 |  339 |  -39 | null | null | null | 107 | null | null | null | null | null
B3   | 166 |  251 | null | null | null | null | null | 128 | null | null | null | null | null
B4   | 116 | null | null | null | null | null | null | 160 | null | null | null | null | null

db<>fiddle here