1|24-jan-11|n1|89|17|81|6|40
2|24-jan-11|n1|21|15|42|67|11
3|24-jan-11|n1|31|17|45|70|69
4|24-jan-11|n1|74|88|47|56|14
5|28-jan-11|n2|31|25|75|37|84
6|28-jan-11|n2|15|4|20|34|68
7|28-jan-11|n2|19|15|81|14|67
8|28-jan-11|n2|47|17|15|71|14
我有一个MySQL表,其中包含每天的数字数组(上面的显示2011年1月24日和2011年1月28日的数字)。每个数字都是1 and 90
之间的任意数字。
我需要在同一行中找到与2天相同的数字对。
例如:
row #2 (January 24, 2011) contains 15 and 67
row #7 (January 28, 2011) also contains 15 and 67
row #4 (January 24, 2011) contains 47 and 14
row #8 (January 28, 2011) also contains 47 and 14
脚本应该返回:
"15" and "67" in the row "2" and "7"
"47" and "14" in the row "4" and "8"
我的解决方案是使用PHP循环解析表中的所有数字。问题是它需要很长时间才会崩溃。
我可以使用任何数学公式或快速PHP / mySQL函数来完成此任务吗?
答案 0 :(得分:2)
在纯SQL中解决它只是为了好玩,由你来决定它是否足够高效:)
测试数据:
CREATE TABLE yourTable
(`id` int, `date` varchar(9), `col1` varchar(2), `col2` int, `col3` int, `col4` int, `col5` int, `col6` int)
;
INSERT INTO yourTable
(`id`, `date`, `col1`, `col2`, `col3`, `col4`, `col5`, `col6`)
VALUES
(1, '24-jan-11', 'n1', 89, 17, 81, 6, 40),
(2, '24-jan-11', 'n1', 21, 15, 42, 67, 11),
(3, '24-jan-11', 'n1', 31, 17, 45, 70, 69),
(4, '24-jan-11', 'n1', 74, 88, 47, 56, 14),
(5, '28-jan-11', 'n2', 31, 25, 75, 37, 84),
(6, '28-jan-11', 'n2', 15, 4, 20, 34, 68),
(7, '28-jan-11', 'n2', 19, 15, 81, 14, 67),
(8, '28-jan-11', 'n2', 47, 17, 15, 71, 14)
;
它来了:
select
yt1.id, yt2.id,
case when yt1.col2 in (yt2.col2, yt2.col3, yt2.col4, yt2.col5, yt2.col6) then yt1.col2 else null end c1,
case when yt1.col3 in (yt2.col2, yt2.col3, yt2.col4, yt2.col5, yt2.col6) then yt1.col3 else null end c2,
case when yt1.col4 in (yt2.col2, yt2.col3, yt2.col4, yt2.col5, yt2.col6) then yt1.col4 else null end c3,
case when yt1.col5 in (yt2.col2, yt2.col3, yt2.col4, yt2.col5, yt2.col6) then yt1.col5 else null end c4,
case when yt1.col6 in (yt2.col2, yt2.col3, yt2.col4, yt2.col5, yt2.col6) then yt1.col6 else null end c5
from
yourTable yt1
,yourTable yt2
where
yt1.date = '24-jan-11'
and yt2.date = '28-jan-11'
and
(
yt1.col2 in (yt2.col2, yt2.col3, yt2.col4, yt2.col5, yt2.col6)
or yt1.col3 in (yt2.col2, yt2.col3, yt2.col4, yt2.col5, yt2.col6)
or yt1.col4 in (yt2.col2, yt2.col3, yt2.col4, yt2.col5, yt2.col6)
or yt1.col5 in (yt2.col2, yt2.col3, yt2.col4, yt2.col5, yt2.col6)
or yt1.col6 in (yt2.col2, yt2.col3, yt2.col4, yt2.col5, yt2.col6)
)
having
case when c1 is null then 0 else 1 end
+ case when c2 is null then 0 else 1 end
+ case when c3 is null then 0 else 1 end
+ case when c4 is null then 0 else 1 end
+ case when c5 is null then 0 else 1 end
>= 2
答案 1 :(得分:0)
“有没有数学公式...”不 - 你没有给我们任何关于数字是如何形成的规则所以我认为唯一的方法就是这样做这是继续比较每个组合。也就是说,你可以采取一些措施来加快速度 - 同样存在会导致脚本崩溃的陷阱。既然你还没有给我们任何代码来处理我的工作,那么我就打算提出一个程序解决方案。
游戏规则
在这个例子中,你的日子将由变量$day[0]
和$day[1]
表示 - 所以你不要重复自己(最后是一个耗时的循环),你可能想要迭代超过一天,并计算每行的所有可能的对组合。为便于查找,这些组合将用作数组键,并将映射到相应的行ID。例如
$pairs = array();
foreach($days[0] as $day){
$len = count($day);
for($i=3;$i<$len;$i++)
for($j=$i+1;$j<$len;$j++){
$key = $day[$j] > $day[$i] ? "{$day[$i]}|{$day[$j]}"
: "{$day[$j]}|{$day[$i]}";
$pairs[$key] = $day[0];
}
}
请注意,为避免必须复制数组键,具体取决于“找到”组合的顺序,我已指定按数字顺序设置键。一旦我们有了这个预先计算的对数组,就可以更容易地在第二天进行传递并确定它具有的共同值。例如
foreach($days[1] as $day){
$len = count($day);
for($i=3;$i<$len;$i++)
for($j=$i+1;$j<$len;$j++){
$key = $day[$j] > $day[$i] ? "{$day[$i]}|{$day[$j]}"
: "{$day[$j]}|{$day[$i]}";
if(isset($pairs[$key]))
echo "\"{$day[$i]}\" and \"{$day[$j]}\" in the row "
. "\"{$pairs[$key]}\" and \"{$day[0]}\"<br/>";
}
}
我会让你为解决方案做好准备,我不确定它如何扩展到大型数据集,但我已经给你足够的工作了 - 你总是可以利用set_time_limit
如果您正在使用特别大的数组。
答案 2 :(得分:0)
它的纯SQL版本。就像tombom一样,为了好玩。
这假设您的数据在原始帖子建议的单个管道分隔字段中。
这是一个单独的SQL,它依赖于一个额外的整数表(称为整数,1列称为i,10行,值为0到9): -
SELECT DISTINCT SubA.TheDate, SubB.TheDate, SubA.TheRowNum, SubB.TheRowNum, SubA.aDelimitedSection, SubB.aDelimitedSection, SubC.aDelimitedSection, SubD.aDelimitedSection,
CONCAT('"', SubA.aDelimitedSection, '" and "', SubC.aDelimitedSection, '" in the row "', SubA.TheRowNum, '" and "', SubB.TheRowNum, '"')
FROM (SELECT SUBSTRING_INDEX(SomeField, '|', 1) TheRowNum, SUBSTRING_INDEX(SUBSTRING_INDEX(SomeField, '|', 2), '|', -1) TheDate, SomeField, SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(SomeField, '|'), '|', Sub1.AnInt), '|', -1) AS aDelimitedSection, Sub1.AnInt
FROM StatsTest,
(SELECT 4+a.i+b.i*10 AS AnInt FROM integers a, integers b) Sub1
WHERE Sub1.AnInt <= (1 + LENGTH(SomeField) - LENGTH( REPLACE ( SomeField, "|", "")))) SubA
INNER JOIN (SELECT SUBSTRING_INDEX(SomeField, '|', 1) TheRowNum, SUBSTRING_INDEX(SUBSTRING_INDEX(SomeField, '|', 2), '|', -1) TheDate, SomeField, SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(SomeField, '|'), '|', Sub1.AnInt), '|', -1) AS aDelimitedSection, Sub1.AnInt
FROM StatsTest,
(SELECT 4+a.i+b.i*10 AS AnInt FROM integers a, integers b) Sub1
WHERE Sub1.AnInt <= (1 + LENGTH(SomeField) - LENGTH( REPLACE ( SomeField, "|", "")))) SubB
ON SubA.aDelimitedSection = SubB.aDelimitedSection AND SubA.TheRowNum < SubB.TheRowNum AND SubA.TheDate != SubB.TheDate
INNER JOIN (SELECT SUBSTRING_INDEX(SomeField, '|', 1) TheRowNum, SUBSTRING_INDEX(SUBSTRING_INDEX(SomeField, '|', 2), '|', -1) TheDate, SomeField, SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(SomeField, '|'), '|', Sub1.AnInt), '|', -1) AS aDelimitedSection, Sub1.AnInt
FROM StatsTest,
(SELECT 4+a.i+b.i*10 AS AnInt FROM integers a, integers b) Sub1
WHERE Sub1.AnInt <= (1 + LENGTH(SomeField) - LENGTH( REPLACE ( SomeField, "|", "")))) SubC
ON SubA.aDelimitedSection < SubC.aDelimitedSection AND SubA.TheRowNum = SubC.TheRowNum
INNER JOIN (SELECT SUBSTRING_INDEX(SomeField, '|', 1) TheRowNum, SUBSTRING_INDEX(SUBSTRING_INDEX(SomeField, '|', 2), '|', -1) TheDate, SomeField, SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(SomeField, '|'), '|', Sub1.AnInt), '|', -1) AS aDelimitedSection, Sub1.AnInt
FROM StatsTest,
(SELECT 4+a.i+b.i*10 AS AnInt FROM integers a, integers b) Sub1
WHERE Sub1.AnInt <= (1 + LENGTH(SomeField) - LENGTH( REPLACE ( SomeField, "|", "")))) SubD
ON SubC.aDelimitedSection = SubD.aDelimitedSection AND SubB.TheRowNum = SubD.TheRowNum
使用您的测试数据在我的机器上的xampp上花费0.014秒,但不确定它是否真的可扩展