从MySQL中的非规范化表查询

时间:2012-12-03 13:12:31

标签: mysql arrays

我有以下数组和一个mysql表,table1

$ arr1 =(“A0”,“A1”,“A2”,“A3”,“A4”)
$ arr2 =(“B0”,“B1”,“B2”,“B3”,“B4”)

+----+-----------------+------+------+
| id | Col1            | Col2 | Col3 |
+----+-----------------+------+------+
|  0 | A0;B1;B2;       | x    | 9    |
|  1 | A0;B1;B2;A1;A2; | x    | 15   |
|  2 | A0;             | x    | 7    |
|  3 | B0;             | x    | 5    |
|  4 | C0;             | j    | 5    |
+----+-----------------+------+------+

我可以查询表中的值,以便最终输出类似于

    +----+-------+------+
    | id |  C31T | C32T |
    +----+-------+------+
    |  0 |  19   |  17  |
    +----+-------+------+

C31T和C32T来自此表

    +----+------+------ +-------+------+------+
    | id | Arr1 | Arr2  |  C31  | C32  | tot  |
    +----+------+-------+-------+------+------+
    |  0 | 1    | 2     |  3    |  6   | 3    |
    |  1 | 3    | 2     |  9    |  6   | 5    |
    |  2 | 1    | 0     |  7    |  0   | 1    |
    |  3 | 0    | 1     |  0    |  5   | 1    |
    +----+------+-------+-------+------+------+

遵循eggyal解决方案我已经坚持到了这一点

    SELECT   table1.id,
         COUNT(DISTINCT arr1.element) AS Arr1,
         COUNT(DISTINCT arr2.element) AS Arr2,
         COUNT(DISTINCT arr1.element) +
         COUNT(DISTINCT arr2.element) AS tot,
(COUNT(DISTINCT arr1.element)/(COUNT(DISTINCT arr1.element)+COUNT(DISTINCT arr2.element)))*col3 AS c31,
(COUNT(DISTINCT arr2.element)/(COUNT(DISTINCT arr1.element)+COUNT(DISTINCT arr2.element)))*col3 AS c32
FROM     table1
  LEFT JOIN (
    SELECT 'A0' AS element
    UNION ALL SELECT 'A1'
    UNION ALL SELECT 'A2'
    UNION ALL SELECT 'A3'
    UNION ALL SELECT 'A4'
  ) arr1 ON FIND_IN_SET(
    arr1.element,
    REPLACE(table1.Col1, ';', ',')
  )
  LEFT JOIN (
    SELECT 'B0' AS element
    UNION ALL SELECT 'B1'
    UNION ALL SELECT 'B2'
    UNION ALL SELECT 'B3'
    UNION ALL SELECT 'B4'
  ) arr2 ON FIND_IN_SET(
    arr2.element,
    REPLACE(table1.Col1, ';', ',')
  )
WHERE    table1.Col2 = 'x'
GROUP BY table1.id

2 个答案:

答案 0 :(得分:1)

我完全同意@Kickstart's comment - 你真的应该normalise你的架构:

CREATE TABLE associations (
  id      INT,
  element VARCHAR(2),
  FOREIGN KEY (id) REFERENCES table1 (id)
);

INSERT INTO associations
  (id, element)
VALUES
  (0, 'A0'), (0, 'B1'), (0, 'B2'),
  (1, 'A0'), (1, 'B1'), (1, 'B2'), (1, 'A1'), (1, 'A2'),
  (2, 'A0'),
  (3, 'B0'),
  (4, 'C0')
;

ALTER TABLE table1 DROP Col1;

然后你的查询将是:

SELECT   table1.id,
         COUNT(DISTINCT arr1.element) AS Arr1,
         COUNT(DISTINCT arr2.element) AS Arr2,
         COUNT(DISTINCT arr1.element) +
         COUNT(DISTINCT arr2.element) AS tot
FROM     table1 JOIN associations USING (id)
  LEFT JOIN (
    SELECT 'A0' AS element
    UNION ALL SELECT 'A1'
    UNION ALL SELECT 'A2'
    UNION ALL SELECT 'A3'
    UNION ALL SELECT 'A4'
  ) arr1 USING (element)
  LEFT JOIN (
    SELECT 'B0' AS element
    UNION ALL SELECT 'B1'
    UNION ALL SELECT 'B2'
    UNION ALL SELECT 'B3'
    UNION ALL SELECT 'B4'
  ) arr2 USING (element)
WHERE    table1.Col2 = 'x'
GROUP BY table1.id

<强> Results

| ID | ARR1 | ARR2 | TOT |
--------------------------
|  0 |    1 |    2 |   3 |
|  1 |    3 |    2 |   5 |
|  2 |    1 |    0 |   1 |
|  3 |    0 |    1 |   1 |

如果没有这样的规范化架构,他所提到的“非常可怕的编码”将是:

SELECT   table1.id,
         COUNT(DISTINCT arr1.element) AS Arr1,
         COUNT(DISTINCT arr2.element) AS Arr2,
         COUNT(DISTINCT arr1.element) +
         COUNT(DISTINCT arr2.element) AS tot
FROM     table1
  LEFT JOIN (
    SELECT 'A0' AS element
    UNION ALL SELECT 'A1'
    UNION ALL SELECT 'A2'
    UNION ALL SELECT 'A3'
    UNION ALL SELECT 'A4'
  ) arr1 ON FIND_IN_SET(
    arr1.element,
    REPLACE(table1.Col1, ';', ',')
  )
  LEFT JOIN (
    SELECT 'B0' AS element
    UNION ALL SELECT 'B1'
    UNION ALL SELECT 'B2'
    UNION ALL SELECT 'B3'
    UNION ALL SELECT 'B4'
  ) arr2 ON FIND_IN_SET(
    arr2.element,
    REPLACE(table1.Col1, ';', ',')
  )
WHERE    table1.Col2 = 'x'
GROUP BY table1.id

<强> Results

| ID | ARR1 | ARR2 | TOT |
--------------------------
|  0 |    1 |    2 |   3 |
|  1 |    3 |    2 |   5 |
|  2 |    1 |    0 |   1 |
|  3 |    0 |    1 |   1 |

更新

在编辑之后,您只需要对现有的查询执行外部查询:

SELECT SUM(Arr1/tot) AS C31T, SUM(Arr2/tot) AS C32T
FROM (

  SELECT   COUNT(DISTINCT arr1.element) * table1.Col3 AS Arr1,
           COUNT(DISTINCT arr2.element) * table1.Col3 AS Arr2,
           COUNT(DISTINCT arr1.element) +
           COUNT(DISTINCT arr2.element) AS tot
  FROM     table1
    LEFT JOIN (
      SELECT 'A0' AS element
      UNION ALL SELECT 'A1'
      UNION ALL SELECT 'A2'
      UNION ALL SELECT 'A3'
      UNION ALL SELECT 'A4'
    ) arr1 ON FIND_IN_SET(
      arr1.element,
      REPLACE(table1.Col1, ';', ',')
    )
    LEFT JOIN (
      SELECT 'B0' AS element
      UNION ALL SELECT 'B1'
      UNION ALL SELECT 'B2'
      UNION ALL SELECT 'B3'
      UNION ALL SELECT 'B4'
    ) arr2 ON FIND_IN_SET(
      arr2.element,
      REPLACE(table1.Col1, ';', ',')
    )
  WHERE    table1.Col2 = 'x'
  GROUP BY table1.id

) t

<强> Results

| C31T | C32T |
---------------
|   19 |   17 |

答案 1 :(得分:1)

有点玩耍。

将表格更改为此类

Table1
+----+------+------+
| id | Col2 | Col3 |
+----+------+------+
|  0 | x    | x    |
|  1 | x    | f    |
|  2 | x    | g    |
|  3 | x    | k    |
|  4 | j    | k    |
+----+------+------+

Table2
+----+----------+------+
| id | Table1id | Col1 |
+----+----------+------+
|  0 | 0        | A0   |
|  1 | 0        | B1   |
|  2 | 0        | B2   |
|  3 | 1        | A0   |
|  4 | 1        | B1   |
|  5 | 1        | B2   |
|  6 | 1        | A1   |
|  7 | 1        | A2   |
|  8 | 2        | A0   |
|  9 | 3        | B0   |
| 10 | 4        | C0   |
+----+-----------------+

然后为您的查询创建一个临时表,其中包含以下内容: -

TempTable
+-------+----------+
| arrno | arrvalue | 
+-------+----------+
| arr1  | A0       |
| arr1  | A1       |
| arr1  | A2       |
| arr1  | A3       |
| arr1  | A4       |
| arr2  | B0       |
| arr2  | B1       |
| arr2  | B2       |
| arr2  | B3       |
| arr2  | B4       |
+-------+----------+

然后您可以像这样使用SQL: -

SELECT table1.id, COUNT(TempTable1.arrvalue), COUNT(TempTable2.arrvalue), COUNT(*)
FROM table1
INNER JOIN table2
ON table1.id = table2.table1id
LEFT OUTER JOIN temptable TempTable1 ON table2.Col1 = TempTable1.arrvalue AND TempTable1.arrno = 'arr1'
LEFT OUTER JOIN temptable TempTable2 ON table2.Col1 = TempTable2.arrvalue AND TempTable2.arrno = 'arr2'
GROUP BY table1.id

有点迟了,但是正在做其他事情,并认为它也可能对你有所帮助。

设置一个名为整数的表,其中一列名为i。 10行,值为0到9.然后,您可以使用它来使用以下SQL

拆分单个字段
SELECT DISTINCT id, SUBSTRING_INDEX(SUBSTRING_INDEX(Col1, ';', anInteger), ';', -1) AS Col1_split, Col2, Col3
FROM table1, 
(SELECT a.i*100+b.i*10+c.i AS anInteger FROM integers a, integers b, integers c) Sub1
HAVING Col1_split <> ''

这可能有助于将分隔字段复制到另一个表中(或者如果您绝望,可以在自己的SQL中将其用作子选择,而不是直接使用该表)。