SQLite如何获取下一行,但是如果当前是最后一行,则获取第一行

时间:2018-08-13 22:49:34

标签: sql sqlite

我有3张桌子。

培训表:

CREATE TABLE `training_session` (
`_id`   INTEGER PRIMARY KEY AUTOINCREMENT,
`date_time` TEXT NOT NULL UNIQUE,
`training_day_id`   INTEGER,
`duration`  INTEGER,
FOREIGN KEY(`training_day_id`) REFERENCES `training_program_day`(`_id`) ON DELETE SET NULL
);

培训计划的天数表:

CREATE TABLE `training_program_day` (
`_id`   INTEGER PRIMARY KEY AUTOINCREMENT,
`name`  TEXT NOT NULL,
`program_id`    INTEGER,
`number`    INTEGER NOT NULL,
FOREIGN KEY(`program_id`) REFERENCES `training_program`(`_id`) ON DELETE CASCADE
);

培训计划表:

CREATE TABLE `training_program` (
`_id`   INTEGER PRIMARY KEY AUTOINCREMENT,
`name`  INTEGER NOT NULL UNIQUE
);

在培训日表中,有一列number确定了培训日在计划中的执行顺序。我从number表中获得了上一个培训日的training_session

SELECT tpd.number
FROM training_session AS ts 
LEFT JOIN training_program_day AS tpd ON ts.training_day_id = tpd._id
WHERE ts.training_day_id IS NOT NULL
ORDER BY ts.date_time
DESC LIMIT 1

我想在下一个训练日获取数据,因此我将上面的代码用作子查询,并找到一个训练日,其编号为1。

SELECT 
tp.name AS program,
tpd.name AS training_day
FROM training_program_day AS tpd
LEFT JOIN training_program AS tp ON tpd.program_id = tp._id
WHERE tpd.number = 1 + (
    SELECT tpd.number
    FROM training_session AS ts 
    LEFT JOIN training_program_day AS tpd ON ts.training_day_id = tpd._id
    WHERE ts.training_day_id IS NOT NULL
    ORDER BY ts.date_time
    DESC LIMIT 1)

如果在子查询中找到的当天的number不是training_prorgam_day表中最大的日期,则此查询正确运行。当然,否则什么也不会回来。但是训练程序中的日期必须循环,因此,如果子查询中找到的number是最大的一天,那么我想获取程序中第一天的数据。但是我不知道该怎么做。我最近开始学习SQLite,因此不了解其所有功能。如果您说我的要求无效,我不会感到惊讶。我将非常感谢您的优化。

例如,我在表中有这样的数据:

training_session
training_session

training_program_day
training_program_day

enter image description here

我想要这个:
result

2 个答案:

答案 0 :(得分:0)

该查询似乎正在运行,但是我认为它可以更轻松,更高效地编写。等待您的优化。

-- 4) Find the data for the day you want
SELECT tp.name AS prog_name, tpd4.name AS day_name, tpd4._id AS day_id
FROM (
  -- 3) If there is no such day, take the first day from this program
  SELECT 
  last_prog_id,
  ifnull(last_number_plus_1, 1) AS desired_number
  FROM (
    -- 2) Looking for a training day from the same program, whose number is 1 more.
    SELECT
    last_prog_id,
    tpd2.number AS last_number_plus_1
    FROM (
      -- 1) Find the training day we trained for the last time
      SELECT
      tpd1.program_id AS last_prog_id,
      tpd1.number AS last_number
      FROM training_session AS ts 
      LEFT JOIN training_program_day AS tpd1 ON ts.training_day_id = tpd1._id
      WHERE ts.training_day_id IS NOT NULL 
      ORDER BY ts.date_time DESC
      LIMIT 1
    )
    LEFT JOIN training_program_day AS tpd2
    ON last_prog_id = tpd2.program_id AND last_number + 1 = tpd2.number
  )
  LEFT JOIN training_program_day AS tpd3
  ON last_prog_id = tpd3.program_id AND last_number_plus_1 = tpd3.number
)
INNER JOIN training_program_day AS tpd4
ON last_prog_id = tpd4.program_id AND desired_number = tpd4.number
INNER JOIN training_program AS tp
ON last_prog_id = tp._id

答案 1 :(得分:0)

子查询last如上所述。 然后,外部查询中的第一个联接将搜索两行,其中第一行具有较大的数字,第二行具有数字1。 然后ORDER BY / LIMIT仅返回编号最大的行,即存在的下一个,否则返回第一个。

SELECT next._id, next.name, p.name
FROM (SELECT d.program_id, d.number
      FROM training_program_day AS d
      JOIN training_session AS s ON d._id = s.training_day_id
      ORDER BY s.date_time DESC
      LIMIT 1) AS last
JOIN training_program_day AS next ON next.program_id = last.program_id
                                 AND next.number IN (last.number + 1, 1)
JOIN training_program AS p ON next.program_id = p._id
ORDER BY next.number DESC
LIMIT 1;