如何使用周围查询中的列作为SQLite中LIMIT的值?

时间:2017-08-23 09:23:11

标签: sql sqlite

在SQLite中,可以使用任何返回或可以转换为整数的表达式作为LIMIT的参数。

  

任何标量表达式都可以在LIMIT子句中使用,只要它计算为整数或可以无损转换为整数的值即可。 [...]

这意味着,以下是可能的(我将在下面显示用于此的数据库):

SELECT * FROM event_attendees
WHERE dtime IS NULL
ORDER BY rtime ASC
LIMIT (
  SELECT max_participants FROM `events` WHERE id = 1
);

此查询将运行并返回结果。

但是,我试图在子查询中使用它,但这给了我一个错误消息。

SELECT *
  FROM `events` e
       JOIN
       event_attendees ON `events`.id = event_attendees.event_id AND 
            event_attendees.id IN (
                SELECT id
                    FROM event_attendees ea2
                    WHERE ea2.dtime IS NULL AND 
                        ea2.event_id = e.id
                    ORDER BY rtime ASC
                    LIMIT e.max_participants
             );

SQLFiddle中,错误消息如下。

  

无法准备声明(1没有这样的专栏:e.max_participants)

当我使用SQLiteStudio 3运行它时,错误信息是:

  

在数据库'foo'上执行SQL查询时出错:没有这样的列events.max_participants

我正在运行的模式如下所示:

CREATE TABLE `events` (
    id               INTEGER PRIMARY KEY AUTOINCREMENT,
    name             VARCHAR,
    max_participants INT
);

CREATE TABLE event_attendees (
    id          INTEGER  PRIMARY KEY AUTOINCREMENT,
    event_id    INTEGER  REFERENCES events (id),
    attendee_id INTEGER, /* we don't need attendees for this example */
    rtime       DATETIME NOT NULL,
    dtime       DATETIME
);

我使用以下示例值。

INSERT INTO `events` ( id, name,  max_participants) 
VALUES               ( 1,  'foo', 3 ), 
                     ( 2,  'bar', 4 );

INSERT INTO `event_attendees` 
(id, event_id, attendee_id, rtime,                 dtime) VALUES
(1,  1,        1,           '2017-08-02 08:08:00', NULL                 ),
(2,  1,        2,           '2017-08-02 08:09:00', NULL                 ),
(3,  1,        3,           '2017-08-02 08:10:00', NULL                 ),
(4,  1,        4,           '2017-08-02 08:12:00', NULL                 ),
(5,  2,        1,           '2017-08-03 08:08:00', NULL                 ),
(6,  2,        2,           '2017-08-03 08:09:00', '2017-08-04 10:08:00'),
(7,  2,        3,           '2017-08-03 08:10:00', NULL                 ),
(8,  2,        4,           '2017-08-03 08:11:00', NULL                 ),
(9,  2,        5,           '2017-08-03 08:12:00', NULL                 ),
(10, 2,        6,           '2017-08-03 08:13:00', NULL                 ),
(11, 2,        7,           '2017-08-03 08:14:00', NULL                 ),
(12, 2,        8,           '2017-08-03 08:15:00', NULL                 );

我还准备了an SQLFiddle with this exact data and both these queries

这些表描述了参与者的事件列表。与attendee_id相关的用户表与问题无关,因此我将其删除了。

我正在尝试选择首先注册该活动的人(rtime),未取消(dtime),受活动的max_participants与会者上限限制。我们应该看到的结果是具有这些event_attendees.id s。

的行
id event_id attendee_id
1  1        1
2  1        2
3  1        3
5  2        1
7  2        3
8  2        4
9  2        5

似乎SQLite无法在子查询中看到外部查询中的e.max_participants列。

我错过了什么,或者这是不可能的,因为我不知道有些限制?还有另一种方法吗?

1 个答案:

答案 0 :(得分:2)

评论太长了。

SQLite确实describe限制表达式的规则:

  

任何标量表达式都可以在LIMIT子句中使用

但是,文档中未定义scalar expression。我认为对它的更好描述将是"标量常数"。

如果您将第一个查询更改为:

SELECT ea.*
FROM event_attendees ea
WHERE dtime IS NULL
ORDER BY rtime ASC
LIMIT (SELECT e.max_participants FROM `events` e WHERE e.id = ea.event_id);

然后您将了解SQLite解析器所具有的问题。 LIMIT需要是一个常量,但它会从一行变为另一行。

似乎SQLite将此扩展为禁止相关子查询。我不完全理解SQLite的内部。我可以想象在解析和执行LIMIT查询之前解析并执行SELECT子句。因此,它无法使用外部查询中的表。这是推测,但它可以解释正在发生的事情。

不幸的是,SQLite不支持窗口功能或类似功能。所以,做你想做的事情是相当复杂和计算上昂贵的。你可能最好在应用层做这件事。