合并等效的第n个非空值 - MySQL

时间:2013-01-29 07:29:08

标签: mysql

我在这个问题上一直在撕扯我的头发。我正在使用现有数据集,需要从表A中的列中删除所有空值并将它们分流,以便按照表B中的顺序排序

我需要的东西相当于Coalesce,但要检索第n个值,这样我就可以像在表B中那样对结果进行排序

我有什么:

表A

Name CURRENT OCT12 SEPT12 AUG12 JUL12 JUN12  MAY12 APR12
---------------------------------------------------------
A    NULL    NULL  Aug-12 NULL  NULL  Jun-12 NULL  Apr-12
B    Nov-12  NULL  Aug-12 NULL  Jul-12Jun-12 NULL  Apr-12

我需要什么:

表B

Name Change1 Change2 Change3 Change4 Change5 Change6
----------------------------------------------------
A    Aug-12  Jun-12  Apr-12  NULL    NULL    NULL   
B    Nov-12  Aug-12  Jul-12  Jun-12  Apr-12  NULL

代码方面,它将类似于:

Select

first non-null value as Change1  
,second non-null value as Change2  
,third non-null value as Change3  
,fourth non-null value as Change4  
,fifth non-null value as Change5...etc..  

from Table_A

我正在使用MySQL,我不知道如何引用第n个非null值以便将它们调用到Table_B中

有没有人有任何想法?

2 个答案:

答案 0 :(得分:0)

我不确定是否会推荐使用此解决方案...数据的规范化始终是更好的选择,但我想使用普通的SQL来回答一些字​​符串函数。此查询应返回您要查找的内容:

SELECT
  Name,
  Changes,
  REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING_INDEX(Changes, ',', 1)), ',', 1)) as Change1,
  REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING_INDEX(Changes, ',', 2)), ',', 1)) as Change2,
  REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING_INDEX(Changes, ',', 3)), ',', 1)) as Change3,
  REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING_INDEX(Changes, ',', 4)), ',', 1)) as Change4,
  REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING_INDEX(Changes, ',', 5)), ',', 1)) as Change5,
  REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING_INDEX(Changes, ',', 6)), ',', 1)) as Change6
FROM (
  SELECT
    Name,
    CONCAT_WS(',', CURRENT, OCT12, SEPT12, AUG12, JUL12, JUN12, MAY12, APR12, ',') as Changes
  FROM
    TableA
) s

我在逗号分隔的字符串中连接所有值,在字符串的末尾有两个逗号(无论如何,一个逗号就足够了,但是更容易放两个,只是忽略最后一个......),因为我正在使用CONCAT_WS,它会自动跳过空值,结果字符串将类似于Aug-12,Jun-12,Apr-12,,

然后在外部查询中,我使用SUBSTRIG_INDEX提取字符串的第n个元素。我建议对数据库进行规范化,但如果你需要快速修复,这个解决方案可能是一个很好的起点。

看到它正常工作here

请注意,我没有返回没有更改的NULL值,但我返回的是空字符串。如果需要,可以更改。

答案 1 :(得分:0)

如果您不想使用字符串函数,则可以使用unpivot和行号分区来尝试使用此sql:

CREATE TABLE #TableA
  ( 
    "Name" VARCHAR(10),
    "CURRENT" VARCHAR(10),
    OCT12 VARCHAR(10),
    SEPT12 VARCHAR(10),
    AUG12 VARCHAR(10),
    JUL12 VARCHAR(10),
    JUN12 VARCHAR(10),
    MAY12 VARCHAR(10),
    APR12 VARCHAR(10)
  ) 

INSERT INTO #TableA
  ("Name", "CURRENT", OCT12, SEPT12, AUG12, JUL12, JUN12, MAY12, APR12)
VALUES
  ('A', NULL, NULL, 'Aug-12', NULL, NULL, 'Jun-12', NULL, 'Apr-12'),
  ('B', 'Nov-12', NULL, 'Aug-12', NULL, 'Jul-12', 'Jun-12', NULL, 'Apr-12')

SELECT * FROM #TableA;



Select "Name",
    Min(Case row_num When 1 Then data End) Change1,
    Min(Case row_num When 2 Then data End) Change2,
    Min(Case row_num When 3 Then data End) Change3,
    Min(Case row_num When 4 Then data End) Change4,
    Min(Case row_num When 5 Then data End) Change5,
    Min(Case row_num When 6 Then data End) Change6
From
(
    select "Name",data,DBColumnName, 
        ROW_NUMBER() OVER (PARTITION BY "Name" ORDER BY "Name") row_num 
    From #TableA
    unpivot (data for DBColumnName in ("CURRENT",OCT12,SEPT12,AUG12,JUL12,JUN12,MAY12,APR12) ) as z
) TableB
group by "Name";

参考:

-TSQL Pivot without aggregate function

-https://www.sqlservertutorial.net/sql-server-window-functions/sql-server-row_number-function/

-https://docs.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-ver15