编写查询检索第一个值而不使用top,fetch,limit

时间:2018-05-16 12:09:15

标签: sql postgresql

对于一个项目,我必须在SQL中编写一个查询(在PostgreSQL上),该查询检索第一位死于艺术家的艺术家,名为“Louis Armstrong”。 在查询中,我不能使用FETCH,TOP,ROWNUM,LIMIT。

这些是我的表

   ARTIST
   ID(PK)
   GID(PK)
   NAME(PK)
   SORT_NAME(PK)
   BEGIN_DATE_YEAR
   BEGIN_DATE_MONTH
   BEGIN_DATE_DAY
   TYPE(FK) --(TYPE NUMBER)

   ARTIST_TYPE
   ID(PK)
   NAME(PK)--(PERSON,GROUP,OTHER)

这是我写下的查询,是正确的,但我不能使用LIMIT子句

   SELECT A.NAME, 
   CONCAT_WS('/',A.BEGIN_DATE_DAY::text,A.BEGIN_DATE_MONTH::text,
   A.BEGIN_DATE_YEAR::text) AS DATA_NASCITA,
   CONCAT_WS('/',A.END_DATE_DAY::text,A.END_DATE_MONTH::text,
   A.END_DATE_YEAR::text) AS DATA_MORTE
   FROM artist AS A
   JOIN artist_type AS AT ON A.TYPE = AT.ID
   WHERE AT.NAME LIKE 'Per%' AND A.END_DATE_YEAR > ALL 
                (SELECT A.END_DATE_YEAR FROM artist AS A
                 JOIN artist_type AS AT ON A.TYPE = AT.ID
                 WHERE AT.NAME LIKE 'Per%' AND A.END_DATE_YEAR <= ALL
                     (
                         SELECT A.END_DATE_YEAR FROM artist AS A
                         JOIN artist_type AS AT ON A.TYPE = AT.ID
                         WHERE AT.NAME LIKE 'Per%' AND A.NAME LIKE 'Lou%'
                     )
                 )
           ORDER BY A.END_DATE_YEAR ASC
           LIMIT 1

3 个答案:

答案 0 :(得分:0)

如果你想制作令人费解的慢代码,你可以试试这个......

SELECT DISTINCT

  FIRST_VALUE(
    A.NAME
  ) OVER END_DATE_YEAR_ASC
                               AS NAME,
  FIRST_VALUE(
    CONCAT_WS('/',A.BEGIN_DATE_DAY::text,A.BEGIN_DATE_MONTH::text,A.BEGIN_DATE_YEAR::text)
  ) OVER END_DATE_YEAR_ASC
                               AS DATA_NASCITA,
  FIRST_VALUE(
    CONCAT_WS('/',A.END_DATE_DAY::text,A.END_DATE_MONTH::text,A.END_DATE_YEAR::text)
  ) OVER END_DATE_YEAR_ASC
                               AS DATA_MORTE
FROM
  <your query, without the ORDER BY>
WINDOW
  END_DATE_YEAR_ASC AS (ORDER BY A.END_DATE_YEAR)


但是,WHERE条款“可疑”......

首先...

  • > ALL(<some dates) == > ( MAX(<some_dates>) )
  • <= ALL(<some dates) == <= ( MIN(<some_dates>) )

除非你期待NULL在那里?

所以,这给了......

WHERE
      AT.NAME LIKE 'Per%'
  AND A.END_DATE_YEAR
      >
      (
        # Latest [END_DATE_YEAR]
        #   Where that [END_DATE_YEAR] is before (or equal to)
        #     Earliest [END_DATE_YEAR] for 'Lou%'
        ############################################################
        SELECT MAX(A.END_DATE_YEAR)
          FROM artist AS A
          JOIN artist_type AS AT ON A.TYPE = AT.ID
         WHERE AT.NAME LIKE 'Per%'
           AND A.END_DATE_YEAR
               <=
               (
                 # Earliest [END_DATE_YEAR] for 'Lou%'
                 ############################################################
                 SELECT MIN(A.END_DATE_YEAR)
                   FROM artist AS A
                   JOIN artist_type AS AT ON A.TYPE = AT.ID
                  WHERE AT.NAME LIKE 'Per%'
                    AND A.NAME LIKE 'Lou%'
               )
      )
  • 查找所有Lou%艺术家的最早死亡日期。
  • 找出之前发生的最新死亡日期。
  • 找出之后发生的最早的死亡。

这不是第一个'Lou%'死亡的死亡吗?

答案 1 :(得分:0)

我认为你被禁止使用FETCH, TOP, ROWNUM, LIMIT 所以这只是使用过的逻辑问题,尝试重现这个伪代码:

select *
from artists a
where a.deathDate > (select deatheDate from artists where name = 'Louis Armstrong')
    and not exists (
        select 1
        from artists b
        where b.deathDate < a.deathDate
)

警告! 可以有多个匹配您的条件。

答案 2 :(得分:0)

我相信你打算写的......

WITH
  artist_per AS
(
  SELECT *
    FROM artist        AS A
    JOIN artist_type   AS AT   ON AT.ID = A.TYPE
   WHERE AT.name LIKE 'Per%'
)
SELECT
  NAME,
  CONCAT_WS('/',BEGIN_DATE_DAY::text,BEGIN_DATE_MONTH::text,BEGIN_DATE_YEAR::text) AS DATA_NASCITA,
  CONCAT_WS('/',  END_DATE_DAY::text,  END_DATE_MONTH::text,  END_DATE_YEAR::text) AS DATA_MORTE
FROM
  artist_per
WHERE
  END_DATE = (
              SELECT MIN(END_DATE)
                FROM artist_per
               WHERE END_DATE > (
                                 SELECT MIN(END_DATE)
                                   FROM artist_per
                                  WHERE NAME LIKE 'Lou%'
                                )
             )

如果只有一个人在Lou%死后立即死亡,将返回一行。