我有一个名为articles
的表格,其中包含以下格式的数据:
id|categories
--+----------
1|123,13,43
2|1,3,15
3|9,17,44,18,3
出于测试目的,您可以使用以下SQL命令创建此表:
CREATE TABLE articles(id INTEGER PRIMARY KEY, categories TEXT);
INSERT INTO articles VALUES(1, '123,13,43'), (2, '1,3,15'), (3, '9,17,44,18,3');
现在我想拆分categories
列的值,以便得到如下表格的结果:
id|category
--+--------
1|123
1|13
1|43
2|1
2|3
2|15
3|9
3|17
3|44
3|18
3|3
如您所见,我想将原始表格带入First normal form。
我已经知道如何从this回答以这种方式拆分一个行。下面的代码示例只占用第二行(即id = 2的那一行)并按所需方式拆分它们:
WITH split(article_id, word, str, offsep) AS
(
VALUES
(
2,
'',
(SELECT categories FROM articles WHERE id=2),
1
)
UNION ALL
SELECT
article_id,
substr(str, 0, CASE WHEN instr(str, ',') THEN instr(str, ',') ELSE length(str)+1 END),
ltrim(substr(str, instr(str, ',')), ','),
instr(str, ',')
FROM split
WHERE offsep
) SELECT article_id, word FROM split WHERE word!='';
当然这非常不灵活,因为文章ID需要硬编码。那么,现在我的问题是:我需要添加或更改上层SQLite代码以使其在所有行上运行并输出所需的结果?
答案 0 :(得分:3)
经过一番游戏,我终于找到了自己的解决方案。它还会处理''
或NULL
作为categories
的值的行:
-- create temporary table which buffers the maximum article ID, because SELECT MAX can take a very long time on huge databases
DROP TABLE IF EXISTS max_article_id;
CREATE TEMP TABLE max_article_id(num INTEGER);
INSERT INTO max_article_id VALUES((SELECT MAX(id) FROM articles));
WITH RECURSIVE split(article_id, word, str, offsep) AS
(
VALUES ( 0, '', '', 0 ) -- begin with dummy article 0 (which does not actually exist) to avoid code duplication
UNION ALL
SELECT
CASE WHEN offsep==0 OR str IS NULL
THEN article_id+1 -- go to next article if the current one is finished
ELSE article_id -- and keep the current one in the opposite case
END,
CASE WHEN offsep==0 OR str IS NULL
THEN ''
ELSE substr(str, 0, CASE WHEN instr(str, ',') THEN instr(str, ',') ELSE length(str)+1 END)
END,
CASE WHEN offsep==0 OR str IS NULL -- when str==NULL, then there has been a NULL value for the categories cell of the current article
THEN (SELECT categories FROM articles WHERE id=article_id+1)
ELSE ltrim(substr(str, instr(str, ',')), ',')
END,
CASE WHEN offsep==0 OR str IS NULL -- offsep==0 means that the splitting was finished in the previous iteration
THEN 1 -- offsep==1 means that splitting the categories for a new article will begin in the next iteration
ELSE instr(str, ',') -- the actual string splitting stuff is explained and taken from here: http://stackoverflow.com/a/32051164
END
FROM split
WHERE article_id<=(SELECT * FROM max_article_id) -- stop getting new articles when the maximum article ID is reached
) SELECT article_id, word AS category FROM split WHERE word!=''; -- only select article_id and word from the result to use output the desired table layout
答案 1 :(得分:0)
嗨,这可能要晚了几年,但是我使用How to split comma-separated value in SQLite?
中的修订答案有了一个更简单的解决方案id|category
1|123
1|13
1|43
2|1
2|3
2|15
3|9
3|17
3|44
3|18
3|3
输出符合预期:
cell.btnlike.addTarget(self, action: #selector(buttonbtnlikePressed(_:event:)), for: .touchUpInside)
@objc func buttonbtnlikePressed(_ sender: Any, event: Any) {
let point : CGPoint = (sender as AnyObject).convert(CGPoint.zero, to:tblPost)
var indexPath = self.tblPost!.indexPathForRow(at: point)
if let btnlike = sender as? UIButton{
if btnlike.isSelected{
btnlike.isSelected = false
}else{
btnlike.isSelected = true
}
}
}