Mysql Rails基于真值表计算唯一记录的复杂查询
使用Rails。我有以下代码:Mysql Rails基于真值表计算唯一记录的复杂查询,mysql,sql,ruby-on-rails,Mysql,Sql,Ruby On Rails,使用Rails。我有以下代码: class-TypeOfBlock1,“T”=>1,“UP”=>2} 提供的答案是正确的。我只想说: 如您所见,查询不会返回零计数,这必须是 在ruby代码中解决(可能使用所有组合初始化哈希) 然后与查询计数合并) 可以通过使用纯MySQL实现: SELECT sub.combination, COALESCE(cnt, 0) AS cnt FROM (SELECT GROUP_CONCAT(Name ORDER BY Name SEPARATOR ' + ')
class-TypeOfBlock
使用以下几组表格:
╔══════════════╗
║块的类型║
╠══════╦═══════╣
║ 身份证件║ 名称║
╠══════╬═══════╣
║ 1.║ 向上的║
║ 2.║ 陆上通信线║
║ 3.║ T║
╚══════╩═══════╝
╔═══════════════════════════════╗
║ 患者\u类型\u块║
╠══════════════════╦════════════╣
║ 块id的类型║ 病人编号║
╠══════════════════╬════════════╣
║ 1.║ 1.║
║ 1.║ 2.║
║ 2.║ 2.║
║ 3.║ 3.║
║ 2.║ 4.║
║ 1.║ 5.║
║ 1.║ 6.║
║ 2.║ 6.║
║ 3.║ 6.║
╚══════════════════╩════════════╝
我想根据区块组合的类型计算唯一患者的数量,以下是预期结果:
#预期结果(就像真值表)
UP(仅具有类型为1的患者)=2名患者
UP+LL(类型为1和2的患者)=1名患者
UP+T(类型为1和3的患者)=0名患者
LL(仅限类型为2的患者)=1名患者
LL+T(具有类型为2和3的患者)=0名患者
T(仅具有类型为3的患者)=1名患者
UP+LL+T(类型为1、2和3的患者)=1名患者
我尝试加入如下表:
up\ll=
块的类型。
联接(“联接患者\u块的类型\u块上的患者\u块的类型\u块。类型\u块的类型\u块的id=类型\u块的类型\u块的id”)。
其中(“患者\u类型\u块中的\u块。患者\u类型\u块中的\u块id=1,患者\u类型\u块中的\u块。患者\u类型\u块中的\u块id=2”)。
大小
但这太复杂了,数字是错误的。我想尝试原始SQL,但Rails 4不推荐使用它,并要求我执行ModelClass.find\u by\u SQL
如何生成上述预期结果?我想到的唯一解决方案是使用原始SQL并利用,如图所示 需要的SQL是:
选择
组合,
将(*)计数为cnt
从(
挑选
ptb.patient_id,
组_concat(tb.name按tb.name排序)作为组合
来自\u块tb的类型\u
内部连接患者\u类型\u块ptb上的ptb。类型\u块\u id=tb.id
按ptb分组。患者id)患者组合
组合分组;
内部选择由患者分组,并选择每个患者拥有的块类型组合。然后,外部选择只对每个组合中的患者进行计数
查询将返回以下内容(请参阅):
正如您所看到的,查询不会返回零计数,这必须在ruby代码中解决(可能会使用零的所有组合初始化哈希,然后与查询计数合并)
要将此查询集成到ruby,只需在任何模型上使用find\u by\u sql
方法(例如,将结果转换为哈希):
sql=1,“LL,T,UP”=>1,“LL,UP”=>1,“T”=>1,“UP”=>2}
提供的答案是正确的。我只想说:
如您所见,查询不会返回零计数,这必须是
在ruby代码中解决(可能使用所有组合初始化哈希)
然后与查询计数合并)
可以通过使用纯MySQL实现:
SELECT sub.combination, COALESCE(cnt, 0) AS cnt
FROM (SELECT GROUP_CONCAT(Name ORDER BY Name SEPARATOR ' + ') AS combination
FROM (SELECT p.Name, p.rn, LPAD(BIN(u.N + t.N * 10), size, '0') bitmap
FROM (SELECT @rownum := @rownum + 1 rn, id, Name
FROM type_of_blocks, (SELECT @rownum := 0) r) p
CROSS JOIN (SELECT 0 N UNION ALL SELECT 1
UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7
UNION ALL SELECT 8 UNION ALL SELECT 9) u
CROSS JOIN (SELECT 0 N UNION ALL SELECT 1
UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7
UNION ALL SELECT 8 UNION ALL SELECT 9) t
CROSS JOIN (SELECT COUNT(*) AS size FROM type_of_blocks) o
WHERE u.N + t.N * 10 < POW(2, size)
) b
WHERE SUBSTRING(bitmap, rn, 1) = '1'
GROUP BY bitmap
) AS sub
LEFT JOIN (
SELECT combination, COUNT(*) AS cnt
FROM (SELECT ptb.patient_id,
GROUP_CONCAT(tb.name ORDER BY tb.name SEPARATOR ' + ') AS combination
FROM type_of_blocks tb
JOIN patients_type_of_blocks ptb
ON ptb.type_of_block_id = tb.id
GROUP BY ptb.patient_id) patient_combinations
GROUP BY combination
) AS sub2
ON sub.combination = sub2.combination
ORDER BY LENGTH(sub.combination), sub.combination;
工作原理:
要更好地了解其工作原理,请参见生成所有社区的Postgresql版本:
WITH all_combinations AS (
SELECT string_agg(b.Name ,' + ' ORDER BY b.Name) AS combination
FROM (SELECT p.Name, p.rn, RIGHT(o.n::bit(16)::text, size) AS bitmap
FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY id)::int AS rn
FROM type_of_blocks )AS p
CROSS JOIN generate_series(1, 100000) AS o(n)
,LATERAL(SELECT COUNT(*)::int AS size FROM type_of_blocks) AS s
WHERE o.n < 2 ^ size
) b
WHERE SUBSTRING(b.bitmap, b.rn, 1) = '1'
GROUP BY b.bitmap
)
SELECT sub.combination, COALESCE(sub2.cnt, 0) AS cnt
FROM all_combinations sub
LEFT JOIN (SELECT combination, COUNT(*) AS cnt
FROM (SELECT ptb.patient_id,
string_agg(tb.name,' + ' ORDER BY tb.name) AS combination
FROM type_of_blocks tb
JOIN patients_type_of_blocks ptb
ON ptb.type_of_block_id = tb.id
GROUP BY ptb.patient_id) patient_combinations
GROUP BY combination) AS sub2
ON sub.combination = sub2.combination
ORDER BY LENGTH(sub.combination), sub.combination;
将所有_组合作为(
选择字符串_agg(b.Name,“+”按b.Name排序)作为组合
从(选择p.Name、p.rn、RIGHT(o.n::bit(16)::文本、大小)作为位图
从(选择*,行号()到(按id排序)::int作为rn
从类型_到类型_块)为p
交叉连接生成_系列(100000)为o(n)
,侧向(选择计数(*)::int作为块类型的大小)作为s
其中o.n<2^尺寸
)b
其中子字符串(b.bitmap,b.rn,1)='1'
按b位图分组
)
选择sub.combination,合并(sub2.cnt,0)作为cnt
从所有_组合子
左连接(选择组合,计数(*)为cnt
从(选择ptb.patient_id、,
字符串_agg(tb.name,“+”按tb.name排序)作为组合
来自\u块tb的类型\u
连接患者\u类型\u块ptb
在ptb.type_of_block_id=tb.id上
按ptb分组。患者id)患者组合
按组合分组)作为子2
关于sub.composition=sub2.composition
按长度排序(子组合),子组合;
您也可以只使用rails 期望
class PatientsTypeOfBlock < ActiveRecord::Base
belongs_to :patient
belongs_to :type_of_block
end
这太棒了。仅仅将此标记为答案并不公平。我会再等一天,然后悬赏你。非常感谢。谢谢你,我的荣幸!:)很高兴你发现了打字错误(我在本地的不同型号上进行了测试)。非常感谢@lad2025。直到。不幸的是,我已经把赏金给了博拉玛。再次感谢。哇!我仍然找到红宝石
╔══════════════╦═════╗
║ combination ║ cnt ║
╠══════════════╬═════╣
║ T ║ 1 ║
║ LL ║ 1 ║
║ UP ║ 2 ║
║ LL + T ║ 0 ║
║ T + UP ║ 0 ║
║ LL + UP ║ 1 ║
║ LL + T + UP ║ 1 ║
╚══════════════╩═════╝
WITH all_combinations AS (
SELECT string_agg(b.Name ,' + ' ORDER BY b.Name) AS combination
FROM (SELECT p.Name, p.rn, RIGHT(o.n::bit(16)::text, size) AS bitmap
FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY id)::int AS rn
FROM type_of_blocks )AS p
CROSS JOIN generate_series(1, 100000) AS o(n)
,LATERAL(SELECT COUNT(*)::int AS size FROM type_of_blocks) AS s
WHERE o.n < 2 ^ size
) b
WHERE SUBSTRING(b.bitmap, b.rn, 1) = '1'
GROUP BY b.bitmap
)
SELECT sub.combination, COALESCE(sub2.cnt, 0) AS cnt
FROM all_combinations sub
LEFT JOIN (SELECT combination, COUNT(*) AS cnt
FROM (SELECT ptb.patient_id,
string_agg(tb.name,' + ' ORDER BY tb.name) AS combination
FROM type_of_blocks tb
JOIN patients_type_of_blocks ptb
ON ptb.type_of_block_id = tb.id
GROUP BY ptb.patient_id) patient_combinations
GROUP BY combination) AS sub2
ON sub.combination = sub2.combination
ORDER BY LENGTH(sub.combination), sub.combination;
class PatientsTypeOfBlock < ActiveRecord::Base
belongs_to :patient
belongs_to :type_of_block
end
PatientsTypeOfBlock.joins( :type_of_block, :patient ).where( "type_of_blocks.name = ?", "UP" ).count