我有一个抽象问题,可以简化为以下问题:假设我们有两个表persons
和names
,如下所示:
SELECT * FROM persons;
+----+-------+--------+
| id | name | fan_of |
+----+-------+--------+
| 1 | alice | 2 |
| 2 | bob | 4 |
| 3 | carol | 1 |
| 4 | dave | 3 |
| 5 | bob | 2 |
+----+-------+--------+
和
SELECT * FROM names;
+----+-------+--------+
| id | name | active |
+----+-------+--------+
| 1 | alice | 1 |
| 2 | bob | 1 |
| 3 | carol | 0 |
| 4 | dave | 1 |
+----+-------+--------+
每个人(persons
)表中的一行都是自己或其他人的粉丝(由id
列中的其他人fan_of
表示)。 names
表包含可以处于活动状态或非活动状态的名称。
对于给定的偏移k
,我想SELECT
persons
个人的k+1
个活动名称作为他们的名字或者其中一个人是他们的粉丝。例如,如果偏移量为1,则第二个活动名称为bob,因此我想选择名称为bob的所有人以及具有其中一个bob的人作为他们的粉丝,在此示例中是一行人id
= 4。这意味着我想得到结果:
+----+------+--------+
| id | name | fan_of |
+----+------+--------+
| 2 | bob | 4 |
| 4 | dave | 3 |
| 5 | bob | 2 |
+----+------+--------+
到目前为止,我得到的是以下查询:
1 SELECT * FROM persons WHERE
2 EXISTS (
3 SELECT * FROM (
4 SELECT * FROM names WHERE active=true LIMIT 1 OFFSET 1
5 ) AS selectedname WHERE (selectedname.name=persons.name)
6 )
7 OR
8 EXISTS (
9 SELECT * FROM(
10 SELECT * FROM persons WHERE EXISTS (
11 SELECT * FROM (
12 SELECT * FROM names WHERE active=true LIMIT 1 OFFSET 1
13 ) AS selectedname WHERE (selectedname.name=persons.name)
14 )
15 ) AS personswiththatname WHERE persons.id=personswiththatname.fan_of
16 );
它从上面给出了我想要的结果,但请注意它是低效的,因为第3-5和11-13行是相同的。
我有以下两个问题:
我实际上需要区分来自的那些行
name
条件(这里是name = bob的行)和那些来的
来自fan_of
条件(此处为name = dave的行)。这个
可以在应用程序代码中完成,但后来我需要另一个
数据库查询之前找出k+1
- 活动名称,这可能
慢一点(如果这是更好的解决方案,请纠正我)。我会
而更喜欢一个帮助我区分的附加列z
像
+----+------+--------+---+
| id | name | fan_of | z |
+----+------+--------+---+
| 2 | bob | 4 | 1 |
| 4 | dave | 3 | 0 |
| 5 | bob | 2 | 1 |
+----+------+--------+---+
如何实现这样的输出?
答案 0 :(得分:1)
看起来我可以使用参数获得你想要达到的最小值(如果这是一个选项)。
它不漂亮,但我看不到一种简单的方法来实现你所要求的东西,所以这就是我到目前为止......(设置@offset以适应'k')
SET @offset = 1;
SET @name = (SELECT name FROM (select name, @rank := @rank +1 as Rank from names n, (SELECT @rank := 0) r where active !=0) as activeRanked where activeRanked.rank = (1 + @offset));
select
a.*
From persons a
where (a.name = @name) OR (a.id IN (SELECT fan_of from persons where name = @name));
如果在我吃完食物的时候你仍然没有答案,我会看第2部分。
(希望我能正确阅读你的简报)
P.S。我把@name SQL保存在一行中,因为在这种情况下它似乎更好。
编辑:这是一个非常混乱但功能性的源指标,使用您的示例。 Z = 1是行来自name
,'0'来自fan_of
SET @offset = 1;
SET @name = (SELECT name FROM (select name, @rank := @rank +1 as Rank from names n, (SELECT @rank := 0) r where active !=0) as activeRanked where activeRanked.rank = (1 + @offset));
select
a.*,'1' as z
From persons a
where (a.name = @name)
union
select
a.*,'0' as z
From persons a
where (a.id IN (SELECT fan_of from persons where name = @name));
不同的ID查询:
SET @offset = 1;
SET @name = (SELECT name FROM (select name, @rank := @rank +1 as Rank from names n, (SELECT @rank := 0) r where active !=0) as activeRanked where activeRanked.rank = (1 + @offset));
SELECT id, name, fan_of, z FROM
(select
distinct a.id,
a.name,
a.fan_of,
1 as z
From persons a
where (a.name = @name)
union
select
distinct a.id,
a.name,
a.fan_of,
0 as z
From persons a
where (a.id IN (SELECT fan_of from persons where name = @name))
ORDER BY z desc) qry
GROUP BY id;
这会产生:
+----+------+--------+---+
| id | name | fan_of | z |
+----+------+--------+---+
| 2 | bob | 4 | 1 |
| 5 | bob | 2 | 1 |
| 4 | dave | 3 | 0 |
+----+------+--------+---+