有没有query/code可以在记录中找到共同值的?
Is there any query/code that can find common values in records?
有人可以指导我(如果有或一些快速代码,可能是简单快速的查询)转换我的 CSV 数据文件(以逗号分隔):
1,A,C,Z,F,G
2,G,Q,R,C,
3,Z,G,Q,
4,C,F,
5,O,P,
6,O,X,Y,J,
7,A,P,X,
我有这个 table 约 1,000,000 条记录
就像您看到的这 7 条记录(在实际数据库中 A、B、C... 是字符串中的单词),记录 1 和 2 在 G 和 C 值以及 2,3 和 1,3 和 ...
如果记录至少有两个共同值,例如记录 1 和 2、3、4(但记录 5、6、7 没有至少 2 个与其他人共享的值),我想同步记录并生成一个列表像这样:
1 A C Z F G Q R
2 G Q R C A Z F
3 Z G Q A C F R
4 C F A Z G Q R
5 O P
6 O X Y J
7 A P X
如果我们对数据进行排序,最后我们必须有 4 条相同的记录,而另外一条没有同步:
1 A C F G Q R Z
2 A C F G Q R Z
3 A C F G Q R Z
4 A C F G Q R Z
5 O P
6 J O X Y
7 A P X
可能我用词不当,请看:
1 A C Z F G
2 G Q R C
记录 1 具有与记录 2 相同的 C 和 G,现在记录 1 没有 R 和 Q,因此我们必须有 1 A C Z F G + Q 和 R,而记录 2 没有 A、Z 和 F,因此我们必须有:2 G Q R C + A、Z 和 F 因此最后我们有:
1 A C Z F G Q R
2 G Q R C A Z F
我需要队列中的所有记录从上到下分别。
写了一个 delphi 代码,但它太慢了。
有人建议我这个 groovy 代码:
def f=[:]
new File('Data.csv').readLines().each{
def items=it.split(',')
def name
items.eachWithIndex { String entry, int i ->
if(i==0){
name=entry
}
else if(entry){
if(!f[entry])
f[entry]=[]
f[entry]<<name
}
}
}
f.findAll {it.value.size()>1}
速度非常快(我想是因为使用了地图文件),但它只能找到共同的值。
如果您想要 SQL 解决方案,那么该 csv 数据可能是
放入一个规范化的 table,数据按 ID 和 WORD 展开。
一旦有了它,table 就变成了自我加入的问题。
并按字母顺序将单词重新组合在一起。
SqlFiddle 测试here
虽然不确定此方法在 table 具有 1000k 条记录的情况下会有多快。
但这是一个有趣的谜题。
示例数据:
DROP TABLE IF EXISTS test_words;
CREATE TABLE IF NOT EXISTS test_words (
id int unsigned NOT NULL PRIMARY KEY,
words varchar(60) NOT NULL
);
INSERT INTO test_words (id, words) VALUES
(1,'A C Z F G'),
(2,'G Q R C'),
(3,'Z G Q'),
(4,'C F'),
(5,'P O'),
(6,'O X Y J'),
(7,'A P X');
计算 table 数字:
DROP TABLE IF EXISTS tmp_numbers;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_numbers (
n int unsigned NOT NULL PRIMARY KEY
);
INSERT INTO tmp_numbers (n) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
展开的话:
DROP TABLE IF EXISTS test_words_unfolded;
CREATE TABLE test_words_unfolded (
word varchar(10) NOT NULL,
id int unsigned NOT NULL,
PRIMARY KEY (word, id)
);
INSERT INTO test_words_unfolded (word, id)
SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(t.words,' ', nr.n),' ',-1) as word, t.id
FROM test_words AS t
JOIN tmp_numbers AS nr
ON CHAR_LENGTH(t.words) - CHAR_LENGTH(REPLACE(t.words,' ','')) >= nr.n - 1
AND SUBSTRING_INDEX(SUBSTRING_INDEX(t.words,' ', nr.n),' ',-1) != '';
结果table:
DROP TABLE IF EXISTS test_result;
CREATE TABLE IF NOT EXISTS test_result (
id int unsigned NOT NULL PRIMARY KEY,
words varchar(60) NOT NULL
);
INSERT INTO test_result (id, words)
SELECT q.id, GROUP_CONCAT(DISTINCT t3.word ORDER BY t3.word ASC SEPARATOR ' ') as words
FROM
(
SELECT t1.id, t2.id as id2
FROM test_words_unfolded t1
JOIN test_words_unfolded t2 ON t1.word = t2.word
GROUP BY t1.id, t2.id
HAVING COUNT(*) > 1 OR t1.id = t2.id
) q
LEFT JOIN test_words_unfolded t3 ON t3.id = q.id2
GROUP BY q.id
ORDER BY q.id;
SELECT *
FROM test_result
ORDER BY id;
结果:
id words
-- -----
1 A C F G Q R Z
2 A C F G Q R Z
3 A C F G Q R Z
4 A C F G Z
5 O P
6 J O X Y
7 A P X
额外
为了标记已经添加的词,填充结果的查询table变得有点复杂。
SELECT
q2.id,
GROUP_CONCAT(DISTINCT CASE WHEN q2.ori = 1 THEN q2.word ELSE CONCAT('[',q2.word,']') END ORDER BY q2.word ASC SEPARATOR ' ') as words
FROM
(
SELECT
q1.id, t3.word,
MAX(CASE WHEN q1.id = t3.id THEN 1 ELSE 0 END) as ori
FROM
(
SELECT
t1.id, t2.id as id2
FROM test_words_unfolded t1
JOIN test_words_unfolded t2 ON t1.word = t2.word
GROUP BY t1.id, t2.id
HAVING COUNT(*) > 1 OR t1.id = t2.id
) q1
LEFT JOIN test_words_unfolded t3 ON t3.id = q1.id2
GROUP BY q1.id, t3.word
) q2
GROUP BY q2.id
ORDER BY q2.id;
结果:
id words
-- -----
1 A C F G [Q] [R] Z
2 [A] C [F] G Q R [Z]
3 [A] [C] [F] G Q [R] Z
4 [A] C F [G] [Z]
5 O P
6 J O X Y
7 A P X
附加实验here
有人可以指导我(如果有或一些快速代码,可能是简单快速的查询)转换我的 CSV 数据文件(以逗号分隔):
1,A,C,Z,F,G
2,G,Q,R,C,
3,Z,G,Q,
4,C,F,
5,O,P,
6,O,X,Y,J,
7,A,P,X,
我有这个 table 约 1,000,000 条记录 就像您看到的这 7 条记录(在实际数据库中 A、B、C... 是字符串中的单词),记录 1 和 2 在 G 和 C 值以及 2,3 和 1,3 和 ...
如果记录至少有两个共同值,例如记录 1 和 2、3、4(但记录 5、6、7 没有至少 2 个与其他人共享的值),我想同步记录并生成一个列表像这样:
1 A C Z F G Q R
2 G Q R C A Z F
3 Z G Q A C F R
4 C F A Z G Q R
5 O P
6 O X Y J
7 A P X
如果我们对数据进行排序,最后我们必须有 4 条相同的记录,而另外一条没有同步:
1 A C F G Q R Z
2 A C F G Q R Z
3 A C F G Q R Z
4 A C F G Q R Z
5 O P
6 J O X Y
7 A P X
可能我用词不当,请看:
1 A C Z F G
2 G Q R C
记录 1 具有与记录 2 相同的 C 和 G,现在记录 1 没有 R 和 Q,因此我们必须有 1 A C Z F G + Q 和 R,而记录 2 没有 A、Z 和 F,因此我们必须有:2 G Q R C + A、Z 和 F 因此最后我们有:
1 A C Z F G Q R
2 G Q R C A Z F
我需要队列中的所有记录从上到下分别。 写了一个 delphi 代码,但它太慢了。 有人建议我这个 groovy 代码:
def f=[:]
new File('Data.csv').readLines().each{
def items=it.split(',')
def name
items.eachWithIndex { String entry, int i ->
if(i==0){
name=entry
}
else if(entry){
if(!f[entry])
f[entry]=[]
f[entry]<<name
}
}
}
f.findAll {it.value.size()>1}
速度非常快(我想是因为使用了地图文件),但它只能找到共同的值。
如果您想要 SQL 解决方案,那么该 csv 数据可能是 放入一个规范化的 table,数据按 ID 和 WORD 展开。
一旦有了它,table 就变成了自我加入的问题。 并按字母顺序将单词重新组合在一起。
SqlFiddle 测试here
虽然不确定此方法在 table 具有 1000k 条记录的情况下会有多快。
但这是一个有趣的谜题。
示例数据:
DROP TABLE IF EXISTS test_words;
CREATE TABLE IF NOT EXISTS test_words (
id int unsigned NOT NULL PRIMARY KEY,
words varchar(60) NOT NULL
);
INSERT INTO test_words (id, words) VALUES
(1,'A C Z F G'),
(2,'G Q R C'),
(3,'Z G Q'),
(4,'C F'),
(5,'P O'),
(6,'O X Y J'),
(7,'A P X');
计算 table 数字:
DROP TABLE IF EXISTS tmp_numbers;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_numbers (
n int unsigned NOT NULL PRIMARY KEY
);
INSERT INTO tmp_numbers (n) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
展开的话:
DROP TABLE IF EXISTS test_words_unfolded;
CREATE TABLE test_words_unfolded (
word varchar(10) NOT NULL,
id int unsigned NOT NULL,
PRIMARY KEY (word, id)
);
INSERT INTO test_words_unfolded (word, id)
SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(t.words,' ', nr.n),' ',-1) as word, t.id
FROM test_words AS t
JOIN tmp_numbers AS nr
ON CHAR_LENGTH(t.words) - CHAR_LENGTH(REPLACE(t.words,' ','')) >= nr.n - 1
AND SUBSTRING_INDEX(SUBSTRING_INDEX(t.words,' ', nr.n),' ',-1) != '';
结果table:
DROP TABLE IF EXISTS test_result;
CREATE TABLE IF NOT EXISTS test_result (
id int unsigned NOT NULL PRIMARY KEY,
words varchar(60) NOT NULL
);
INSERT INTO test_result (id, words)
SELECT q.id, GROUP_CONCAT(DISTINCT t3.word ORDER BY t3.word ASC SEPARATOR ' ') as words
FROM
(
SELECT t1.id, t2.id as id2
FROM test_words_unfolded t1
JOIN test_words_unfolded t2 ON t1.word = t2.word
GROUP BY t1.id, t2.id
HAVING COUNT(*) > 1 OR t1.id = t2.id
) q
LEFT JOIN test_words_unfolded t3 ON t3.id = q.id2
GROUP BY q.id
ORDER BY q.id;
SELECT *
FROM test_result
ORDER BY id;
结果:
id words
-- -----
1 A C F G Q R Z
2 A C F G Q R Z
3 A C F G Q R Z
4 A C F G Z
5 O P
6 J O X Y
7 A P X
额外
为了标记已经添加的词,填充结果的查询table变得有点复杂。
SELECT
q2.id,
GROUP_CONCAT(DISTINCT CASE WHEN q2.ori = 1 THEN q2.word ELSE CONCAT('[',q2.word,']') END ORDER BY q2.word ASC SEPARATOR ' ') as words
FROM
(
SELECT
q1.id, t3.word,
MAX(CASE WHEN q1.id = t3.id THEN 1 ELSE 0 END) as ori
FROM
(
SELECT
t1.id, t2.id as id2
FROM test_words_unfolded t1
JOIN test_words_unfolded t2 ON t1.word = t2.word
GROUP BY t1.id, t2.id
HAVING COUNT(*) > 1 OR t1.id = t2.id
) q1
LEFT JOIN test_words_unfolded t3 ON t3.id = q1.id2
GROUP BY q1.id, t3.word
) q2
GROUP BY q2.id
ORDER BY q2.id;
结果:
id words
-- -----
1 A C F G [Q] [R] Z
2 [A] C [F] G Q R [Z]
3 [A] [C] [F] G Q [R] Z
4 [A] C F [G] [Z]
5 O P
6 J O X Y
7 A P X
附加实验here