子查询 GROUP_CONCAT 的奇怪结果

Weird result for GROUP_CONCAT on subquery

在子查询上使用 GROUP_CONCAT 时我有一个奇怪的行为。 这是我的查询:

SELECT
  name,
  GROUP_CONCAT(DISTINCT (id) SEPARATOR "-") AS id
FROM (
       (SELECT
          "APN"                                          AS name,
          GROUP_CONCAT(DISTINCT (site.id) SEPARATOR "-") AS id
        FROM site
        WHERE id IN
              (138, 147, 8918, 8916, 9033, 9240, 97, 9038, 8886, 9036, 9067, 146, 37, 9127, 52, 9031, 23, 8635, 8665, 
               46, 39, 18, 33, 9035, 137, 9051, 8766, 25, 20, 9160, 133, 8636, 9021, 8655, 21, 42, 8757, 22, 9017, 77, 
               9037, 44, 49, 9323, 55, 74, 150, 8, 67, 1, 8928, 58, 9025, 9221, 9019, 9069, 9214, 9176, 95, 40, 9335, 
               168, 9260, 8641, 9227, 9258, 24, 50, 29, 9073, 12, 36, 8882, 9, 43, 76, 9032, 51, 9060, 96, 8922, 9212,
               14, 9095, 28, 9213, 31, 41, 68, 9027, 8884, 9023, 9059, 9034, 9016, 11, 61, 9229, 8761, 9225, 8937, 9018,
               9121, 9119, 8659, 8926, 9096, 57, 9083, 8662, 9232, 149, 8643, 88, 19, 8660, 10, 8936, 9210, 9241, 17, 8872))
       UNION ALL
       (SELECT
          "smart"                                        AS name,
          GROUP_CONCAT(DISTINCT (site.id) SEPARATOR "-") AS id
        FROM site
        WHERE id IN
              (9129, 8981, 9136, 9169, 9170, 9171, 9172, 9297, 9147, 9155, 9139, 9138, 9142, 9296, 8987, 9216, 9252,
               9320, 8951, 8945, 8952, 8965, 8963, 9012, 9192, 8938, 8941, 8968, 8977, 9117, 9135, 9140, 9143, 9295,
               9298, 9137, 8988, 8989, 8992, 9164, 9156, 9165, 9168, 9173, 8953, 8999, 8939, 8940, 8942, 8943, 8954,
               8956, 8957, 8959, 8960, 8964, 8971, 8972, 8973, 8974, 8982, 9000, 9001, 9003, 8950, 8978, 8979, 8983,
               9002, 9005, 8984, 8955, 8986, 8980, 8993, 9008, 9010, 8949, 8998, 9150, 9122, 8944, 8946, 8948, 9006,
               9009, 9013, 9128, 9215, 9321, 9011, 9154, 8970, 8975, 8994, 9070, 8966, 8958, 9007, 9014))
     ) t
GROUP BY name;

(这是一个 "test" 查询来轻松显示问题,真正的查询不是 "dumb")。它重新组合两个子查询的结果。所有 ID 都存在并且 return 一行。

所以当我 运行 单独第一个子查询时,我得到名称的结果 "APN" 和“ 1-8-9-10-11-12-14-17-18- 19-20-21-22-23-24-25-28-29-31-33-36-37-39-40-41-42-43-44-46-49-50-51-52-55- 57-58-61-67-68-74-76-77-88-95-96-97-133-137-138-146-147-149-150-168-8635-8636-8641-8643-8655- 8659-8660-8662-8665-8757-8761-8766-8872-8882-8884-8886-8916-8918-8922-8926-8928-8936-8937-9016-9017-9018-9019-9021-9023-9025- 9027-9031-9032-9033-9034-9035-9036-9037-9038-9051-9059-9060-9067-9069-9073-9083-9095-9096-9119-9121-9127-9160-9176-9210-9212- ID 为 9213-9214-9221-9225-9227-9229-9232-9240-9241-9258-9260-9323-9335"(完整的 ID 列表)

第二个子查询同理,只是名称为"smart",ID不同。所以这是预期的行为。

问题是当我 运行 完整查询时,对于名称 APN,我得到以下 ID 列表: 1-8-9-10-11-12-14-17-18-19-20-21-22-23-24-25-28-29-31-33-36-37-39-40-41- 42-43-44-46-49-50-51-52-55-57-58-61-67-68-74-76-77-88-95-96-97-133-137-138-146- 147-149-150-168-8635-8636-8641-8643-8655-8659-8660-8662-8665-8757-8761-8766-8872-8882-8884-8886-8916-8918-8922-8926-8928- 8936-8937-9016-9017-9018-9019-9021-9023-9025-9027-9031-9032-9033-9034

所以这个列表比第一个小得多。这与名称 "smart" 相同。

我尝试将我的两个子查询替换为 (SELECT "APN" 作为名称,“1-8-9-10-11-12-14-17-etc...”作为 ID FROM site LIMIT 1) 包含完整的 ID 列表(名称 "smart" 也是如此),并且完整查询的结果符合预期(每个名称的完整 ID 列表)。

group_concat_max_len 在我的服务器上是 1024(我的完整 ID 列表比 1024 个字符小得多)

那么,您知道为什么结果不如预期吗?

你的查询有点奇怪。

select name, GROUP_CONCAT(DISTINCT(id) SEPARATOR "-") AS id FROM (
        (select "APN" AS name, GROUP_CONCAT(DISTINCT(site.id) SEPARATOR "-") AS id  from site WHERE id IN (138,147,8918,8916,9033,9240,97,9038,8886,9036,9067,146,37,9127,52,9031,23,8635,8665,46,39,18,33,9035,137,9051,8766,25,20,9160,133,8636,9021,8655,21,42,8757,22,9017,77,9037,44,49,9323,55,74,150,8,67,1,8928,58,9025,9221,9019,9069,9214,9176,95,40,9335,168,9260,8641,9227,9258,24,50,29,9073,12,36,8882,9,43,76,9032,51,9060,96,8922,9212,14,9095,28,9213,31,41,68,9027,8884,9023,9059,9034,9016,11,61,9229,8761,9225,8937,9018,9121,9119,8659,8926,9096,57,9083,8662,9232,149,8643,88,19,8660,10,8936,9210,9241,17,8872)) 
    UNION ALL 
        (select "smart" AS name, GROUP_CONCAT(DISTINCT(site.id) SEPARATOR "-") AS id from site WHERE id IN (9129,8981,9136,9169,9170,9171,9172,9297,9147,9155,9139,9138,9142,9296,8987,9216,9252,9320,8951,8945,8952,8965,8963,9012,9192,8938,8941,8968,8977,9117,9135,9140,9143,9295,9298,9137,8988,8989,8992,9164,9156,9165,9168,9173,8953,8999,8939,8940,8942,8943,8954,8956,8957,8959,8960,8964,8971,8972,8973,8974,8982,9000,9001,9003,8950,8978,8979,8983,9002,9005,8984,8955,8986,8980,8993,9008,9010,8949,8998,9150,9122,8944,8946,8948,9006,9009,9013,9128,9215,9321,9011,9154,8970,8975,8994,9070,8966,8958,9007,9014))
) t GROUP BY name;

等于:

    (select "APN" AS name, GROUP_CONCAT(DISTINCT(site.id) SEPARATOR "-") AS id  from site WHERE id IN (138,147,8918,8916,9033,9240,97,9038,8886,9036,9067,146,37,9127,52,9031,23,8635,8665,46,39,18,33,9035,137,9051,8766,25,20,9160,133,8636,9021,8655,21,42,8757,22,9017,77,9037,44,49,9323,55,74,150,8,67,1,8928,58,9025,9221,9019,9069,9214,9176,95,40,9335,168,9260,8641,9227,9258,24,50,29,9073,12,36,8882,9,43,76,9032,51,9060,96,8922,9212,14,9095,28,9213,31,41,68,9027,8884,9023,9059,9034,9016,11,61,9229,8761,9225,8937,9018,9121,9119,8659,8926,9096,57,9083,8662,9232,149,8643,88,19,8660,10,8936,9210,9241,17,8872)) 
    UNION ALL 
    (select "smart" AS name, GROUP_CONCAT(DISTINCT(site.id) SEPARATOR "-") AS id from site WHERE id IN (9129,8981,9136,9169,9170,9171,9172,9297,9147,9155,9139,9138,9142,9296,8987,9216,9252,9320,8951,8945,8952,8965,8963,9012,9192,8938,8941,8968,8977,9117,9135,9140,9143,9295,9298,9137,8988,8989,8992,9164,9156,9165,9168,9173,8953,8999,8939,8940,8942,8943,8954,8956,8957,8959,8960,8964,8971,8972,8973,8974,8982,9000,9001,9003,8950,8978,8979,8983,9002,9005,8984,8955,8986,8980,8993,9008,9010,8949,8998,9150,9122,8944,8946,8948,9006,9009,9013,9128,9215,9321,9011,9154,8970,8975,8994,9070,8966,8958,9007,9014))

除非您的原始查询生成许多具有同一组 ID 的 APN 行,否则不需要按名称和 ID 进行父分组。

回到你的问题:你说得对 group_concat 的最大长度为 1024,但排序/联合操作进一步截断为 1/3 (1024/3 = 341)。 (虽然众所周知,但没有官方文件可以支持这一点)

在你的情况下,只需增加组连接的最大长度值:

SET group_concat_max_len = 5000;

这应该会在不截断的情况下提供您想要的输出。

您可以创建临时表并合并它们,或者您可以将 grou_concat 结果输出到一个变量中。在这两种方式中,grop_concat 将被其原始默认值截断。