Mysql 向下筛选所有行的特定条件,并为具有相同值的每列只返回一行

Mysql 向下筛选所有行的特定条件,并为具有相同值的每列只返回一行,mysql,sql,Mysql,Sql,我有房屋租赁和房屋租赁条款,见下表。房屋租赁可以有多个房屋租赁条款,但一次只能有一个有效条款 表定义: CREATE TABLE `house_leases` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `house_id` int(10) unsigned NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `house_lease_terms` ( `id` int(10) unsi

我有房屋租赁和房屋租赁条款,见下表。房屋租赁可以有多个房屋租赁条款,但一次只能有一个有效条款

表定义:

CREATE TABLE `house_leases` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `house_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `house_lease_terms` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `house_lease_id` int(10) unsigned NOT NULL,
  `date_start` datetime NOT NULL,
  `date_end` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `house_lease_terms_house_lease_id_foreign` (`house_lease_id`),
  CONSTRAINT `house_lease_terms_house_lease_id_foreign` FOREIGN KEY (`house_lease_id`) REFERENCES `house_leases` (`id`) ON DELETE CASCADE
);
正如您所看到的,house\u lease\u terms.house\u lease\u id对应于特定的house\u lease,但是可以有多行具有相同的house\u lease\u id

确定有效条款的规则如下:

现在开始日期或结束日期为空

如果未返回任何行,则活动术语必须在将来,因此规则更改为:

开始日期>现在

如果条款不在将来,因为可能返回多行,我们将按日期\u开始描述订购。我们希望最新的日期\u开始显示在结果的顶部。否则,我们按日期开始ASC排序,因为我们希望最接近的日期现在开始在顶部

然后我限制为1,只得到一个结果,该行被视为活动项。如果没有结果返回,则没有活动项

我有一个SQL语句,它具有获取特定房屋租赁id的逻辑。它如下所示:

SELECT * FROM house_lease_terms
WHERE 
CASE 
    WHEN 
        (SELECT COUNT(*) FROM house_lease_terms WHERE date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL) AND house_lease_id = 1)
    THEN 
        date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL)
    ELSE
        date_start > NOW()
END
AND house_lease_id = 1
ORDER BY
    IF(
        (SELECT COUNT(*) FROM house_lease_terms WHERE date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL) AND house_lease_id = 1), 
        unix_timestamp(date_start), 
        -unix_timestamp(date_start)
    ) DESC
LIMIT 1;
这句话很管用,但我希望有更好的方法更有效地获取特定房屋租赁id的有效条款。如果您知道更好的解决方案,请与我们分享

现在,我需要一个查询,它将获取所有不同房屋租赁id的活动条款

我不想要任何类型的自定义MySQL函数或存储过程来实现这一点。我不知道从哪里开始创建此查询。我想我可以在一些子选择或联接中使用上面的查询,但不确定我将如何这样做

任何帮助都将不胜感激

SQLFIDLE数据:

查找:

SELECT *
FROM house_lease_terms
WHERE house_lease_id = 1
  AND (   (   (    date_start <= NOW() 
               AND date_end > NOW()
              ) 
           OR date_end IS NULL
          )
       OR (date_start > NOW()
          )
      )
ORDER BY CASE WHEN ((date_start <= NOW() AND date_end > NOW()) OR date_end IS NULL)
              THEN DATEDIFF(NOW(), date_start)
              ELSE DATEDIFF(date_start, NOW()) + 1000000
              END
下一代

SELECT id, house_lease_id, date_start, date_end
FROM (
SELECT id,
       CASE WHEN @var2=house_lease_id 
            THEN @var1:=@var1+1 
            ELSE @var1:=1
            END row_number_in_house_lease_id,
       @var2:=house_lease_id house_lease_id,
       date_start,
       date_end
FROM house_lease_terms, (SELECT @var1:=0, @var2:=0) variables 
WHERE (   (   (    date_start <= NOW() 
               AND date_end > NOW()
              ) 
           OR date_end IS NULL
          )
       OR (date_start > NOW()
          )
      )
ORDER BY house_lease_id,
         CASE WHEN ((date_start <= NOW() AND date_end > NOW()) OR date_end IS NULL)
              THEN DATEDIFF(NOW(), date_start)
              ELSE DATEDIFF(date_start, NOW()) + 1000000
              END
) AS cte
WHERE row_number_in_house_lease_id = 1;

我不确定这是你认为干净的,但似乎任何方法都会导致一个相当复杂和混乱的查询。 根据您的原始查询:

SELECT house_lease_id, 
       SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY
                                    IF(
                                        (SELECT COUNT(*) FROM house_lease_terms AS hlt2 
                                         WHERE date_start <= NOW() 
                                         AND (date_end > NOW() OR date_end IS NULL) 
                                         AND hlt2.house_lease_id = hlt.house_lease_id), 
                                         unix_timestamp(date_start), 
                                         -unix_timestamp(date_start)
                                    ) DESC),',',1) AS id,
       SUBSTRING_INDEX(GROUP_CONCAT(date_start ORDER BY
                                    IF(
                                        (SELECT COUNT(*) FROM house_lease_terms AS hlt3 
                                         WHERE date_start <= NOW() 
                                         AND (date_end > NOW() OR date_end IS NULL) 
                                         AND hlt3.house_lease_id = hlt.house_lease_id), 
                                         unix_timestamp(date_start), 
                                         -unix_timestamp(date_start)
                                    ) DESC),',',1) AS date_start,
       SUBSTRING_INDEX(GROUP_CONCAT(date_end ORDER BY
                                    IF(
                                        (SELECT COUNT(*) FROM house_lease_terms AS hlt4 
                                         WHERE date_start <= NOW() 
                                         AND (date_end > NOW() OR date_end IS NULL) 
                                         AND hlt4.house_lease_id = hlt.house_lease_id), 
                                         unix_timestamp(date_start), 
                                         -unix_timestamp(date_start)
                                    ) DESC),',',1) AS date_end 
FROM house_lease_terms AS hlt
WHERE 
CASE 
    WHEN 
        (SELECT COUNT(*) FROM house_lease_terms AS hlt5 WHERE date_start <= NOW() 
         AND (date_end > NOW() OR date_end IS NULL) 
         AND hlt5.house_lease_id = hlt.house_lease_id)
    THEN 
        date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL)
    ELSE
        date_start > NOW()
END
GROUP BY hlt.house_lease_id;

这应该行得通。

您使用的是哪个版本的mysql?请按顺序使用用例,而不是按位置使用。版本:5.7.24有效!因此,我现在有一个更优化的查询来获取特定的house\u lease\u id,但仍然需要帮助获取“order子句”中所有house\u lease\u id“sUnknown”列“house\u lease\u terms”的活动术语。我还可以取出房屋租赁id=1,并对所有现行房屋租赁条款进行此提取吗?我只想为每套房子的租赁返回一行_id@JacobHyde更正。我可以取出房屋租赁id=1,并对所有有效的房屋租赁条款进行此提取吗?我只希望为每个房屋返回一行\u lease\u id使用最后一个查询作为MySQL 8+的CTE或子查询。选择您需要的“房屋租赁”id和“房屋租赁”id中的行号为的记录。
SELECT house_lease_id, 
       SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY
                                    IF(
                                        (SELECT COUNT(*) FROM house_lease_terms AS hlt2 
                                         WHERE date_start <= NOW() 
                                         AND (date_end > NOW() OR date_end IS NULL) 
                                         AND hlt2.house_lease_id = hlt.house_lease_id), 
                                         unix_timestamp(date_start), 
                                         -unix_timestamp(date_start)
                                    ) DESC),',',1) AS id,
       SUBSTRING_INDEX(GROUP_CONCAT(date_start ORDER BY
                                    IF(
                                        (SELECT COUNT(*) FROM house_lease_terms AS hlt3 
                                         WHERE date_start <= NOW() 
                                         AND (date_end > NOW() OR date_end IS NULL) 
                                         AND hlt3.house_lease_id = hlt.house_lease_id), 
                                         unix_timestamp(date_start), 
                                         -unix_timestamp(date_start)
                                    ) DESC),',',1) AS date_start,
       SUBSTRING_INDEX(GROUP_CONCAT(date_end ORDER BY
                                    IF(
                                        (SELECT COUNT(*) FROM house_lease_terms AS hlt4 
                                         WHERE date_start <= NOW() 
                                         AND (date_end > NOW() OR date_end IS NULL) 
                                         AND hlt4.house_lease_id = hlt.house_lease_id), 
                                         unix_timestamp(date_start), 
                                         -unix_timestamp(date_start)
                                    ) DESC),',',1) AS date_end 
FROM house_lease_terms AS hlt
WHERE 
CASE 
    WHEN 
        (SELECT COUNT(*) FROM house_lease_terms AS hlt5 WHERE date_start <= NOW() 
         AND (date_end > NOW() OR date_end IS NULL) 
         AND hlt5.house_lease_id = hlt.house_lease_id)
    THEN 
        date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL)
    ELSE
        date_start > NOW()
END
GROUP BY hlt.house_lease_id;