我的问题可能类似于这些问题:
表示例:
source zip phone street city created_at
==================================================================
a 11111 11111 Flatlands null 2015-01-01
b 11111 11111 Flatlands Avenue New York 2015-01-01
c 11111 11111 Ave Flatlands New York 2015-01-01
a 22222 22222 Favory New York 2015-01-01
b 22222 22222 Favory Avenue New York 2017-12-12
c 22222 22222 Ave Favory New York 2015-01-01
b 33333 33333 Sixteenth Washington 2015-01-01
c 33333 33333 st. 16th null 2015-01-01
c 44444 44444 st. West Land null 2015-01-01
假设我有一张表格,其中包含不同城市的地方信息。这些信息来自3个不同的来源:a
,b
和c
。
zip
和phone
字段唯一标识位置,因此数据库中的行可以按这些字段进行分组。
我需要合并各种来源的各种位置信息,根据street
和city
列的规则集选择最佳值。
规则是:
street
和city
的非空值优先于空值。street
和city
来源的a
和b
列的值c
来源(权重(a
)) =权重(b
)>权重(c
))如果这些列不为空。a
和b
,请对具有最新created_at
时间戳的行中的列值进行优先排序。以下是我想收到的结果:
zip phone street city
====================================
11111 11111 Flatlands New York
22222 22222 Favory Avenue New York
33333 33333 Sixteenth Washington
44444 44444 st. West Land null
Here is a DB Fiddle to play with
我不确定这是否可以用SQL实现,也许我最好的选择是切换到NoSQL DB +命令式处理任务。或者只是使用一些工具从数据库中提取信息然后进行处理。
P.S。这是一个简化的例子。
答案 0 :(得分:0)
您可以使用以下查询来实现street
的优先级排序规则:
SELECT zip, phone, street
FROM test
ORDER BY zip, phone,
-- prioritize non empty values over null values
CASE
WHEN (street IS NOT NULL) OR (street = '') THEN 0
ELSE 1
END,
-- prioritize a, b over c
CASE
WHEN source IN ('a', 'b') THEN 0
ELSE 1
END,
-- prioritize rows which have the latest created_at
created_at DESC
类似的查询可用于city
字段。
然后你可以使用变量来模拟ROW_NUMBER
,遗憾的是在MySQL中不可用:
SELECT zip, phone, street,
@seq := IF(@id = CONCAT(zip,phone), @seq + 1,
IF(@id := CONCAT(zip,phone), 1, 1)) AS seq
FROM test
CROSS JOIN (SELECT @seq := 0, @id = '') AS v
ORDER BY zip, phone,
-- prioritize non empty values over null values
CASE
WHEN (street IS NOT NULL) OR (street = '') THEN 0
ELSE 1
END,
-- prioritize a, b over c
CASE
WHEN source IN ('a', 'b') THEN 0
ELSE 1
END,
-- prioritize rows which have the latest created_at
created_at DESC
同样,类似的查询可用于city
字段。
通过在zip
,street
和seq = 1
上加入上述派生表来获得所需的结果。