-1
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 函数可以用来完成此任务?

4

3 回答 3

2

Solved it in pure SQL just for fun, it's up to you to decide if it's performant enough :)

Test data:

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)
;

And here it comes:

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
于 2013-04-08T09:44:35.753 回答
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 秒,但不确定它是否真的可扩展

于 2013-04-08T11:09:11.520 回答
0

“有没有任何数学公式......”不 - 你没有给我们任何关于数字如何产生的规则,据我所知,唯一的方法是继续比较每个组合。也就是说,你可以做一些事情来加快速度——同样的陷阱也会杀死脚本。由于您没有给我们任何代码来使用,我只是要制定一个程序解决方案。


游戏规则

  • 据我了解,您有 2 个变量(数组) - 每天一个。
  • 我不知道“n1”和“n2”的意义(如果有的话),所以我忽略了它们。
  • 您只对两天/日期之间的共同值感兴趣,而不关心可能在同一日期内找到的任何对。

在此示例中,您的日子将由变量表示,$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如果你正在使用特别大的数组,你可以随时使用.

于 2013-04-08T09:43:13.770 回答