如何用 SQL 求出「都关注了某100人」和「都收藏了某100帖子」的所有用户?
sqlite3 test.db \
'CREATE TABLE a (uid INT, num INT, PRIMARY KEY (uid, num)) WITHOUT ROWID' \
'CREATE TABLE b (uid INT, num INT, PRIMARY KEY (uid, num)) WITHOUT ROWID'
stdout
和stderr
C
源码改造成:先往stdout
写,写完就fclose()
,然后再往stderr
写,写完也fclose()
#define each(p, arr) \
(typeof(*(arr)) *p = (arr), *_end = (arr) + sizeof(arr) / sizeof(*(arr)); p < _end; ++p)
int main() {
// 省略...
FILE * outputs[] = {stdout, stderr};
for each (fp_p, outputs) {
// 省略...
fclose(*fp_p);
}
}
shell
执行是这样:
tcc -run main.c \
> >(sqlite3 test.db '.import --csv /dev/stdin a') \
2> >(sqlite3 test.db '.import --csv /dev/stdin b')
结果是,第一个sqlite3
迟迟不结束读取stdin
(即使我在c
里写了fclose(xxx)
),导致第二个sqlite3
也去写入,最后数据库损坏。
改成这样也没用……
tcc -run main.c \
> >(sqlite3 test.db 'begin exclusive' '.import --csv /dev/stdin a' 'commit') \
2> >(sqlite3 test.db 'begin exclusive' '.import --csv /dev/stdin b' 'commit')
C
源码改造成:挨个往argv
里的所有文件写
int main(int argc, char *argv[]) {
// 省略...
for (int argi = 1; argi < argc; ++argi) {
FILE * fp = fopen(argv[argi], "w");
// 省略...
fclose(fp);
}
}
shell
执行是这样:
tcc -run main.c \
>(sqlite3 test.db '.import --csv /dev/stdin a') \
>(sqlite3 test.db '.import --csv /dev/stdin b')
还是不行,结果类似上面的
C
源码改造成:每次结束后,写入特殊标记
int main() {
// 省略...
for (int times = 0; times < 2; ++times) {
// 省略...
puts("END");
}
}
shell
测试的时候,发现都不行:
tcc -run main.c | {
sed '/^END$/Q' | wc -l
sed '/^END$/Q' | wc -l
}
结果:
1199869 # 我只测了 3w 个 uid
0
简化一下问题:
$ seq 10 | { head -n 3; head -n 3; }
1
2
3
???
为何还要多一个『取出所有「稍后我程序自己去连表的主键ID」列表』呢
程序封装的好一点,功能复杂一点,就会发现很多id在你想用它们之前就已经查好放在变量里了,唾手可得,没有必要再专门join。
只有“没有任何封装,每个需求都单独写一个SQL,每个功能都独立出现,不与其他功能进行组合”的编程模式和项目架构,才会出现“多一个查找ID步骤”的烦恼。
比如,要显示这个导航条,我需要帖子所在版块的id。那我会“多一个查找ID的步骤”吗?并不会,因为在显示这个导航条之前,我已经显示了帖子标题,在那时候我就已经用select *
同时得到版块的id了。
首页 > 绿虎论坛 > 编程 > 数据库
所以只要程序复杂一点,界面功能全面一点,那些查询要用的id、名称等数据在实现其他功能时肯定早就提前找好了。
全靠JOIN
解决问题,意味着你需要为每个具体问题写一个单独的SQL。而实际项目是各种需求的组合叠加,“具体问题”的数量以排列组合的数量级增长,写那么多SQL你烦不烦,就看你自己了。
而且,在组合各种功能时,明明在上一个问题里想要的ID都拿到了,在下一个问题里还要JOIN一下重新查一遍,会不会觉得蠢也看你自己了。
@老虎会游泳,我发现
sqlite
也不比脚本语言慢,生成 2亿行,花了 两分半,是tcc
的 7~8 倍耗时但是没有
srand
,所以每次结果都有细微差异结果: