如何编写这个复杂的查询SQL?

时间:2018-12-08 22:44:23

标签: mysql

如果我知道如何按十二生肖的所有符号进行过滤,那么按十二生肖“摩ri座”的符号(从12月22日至1月20日)不知道如何选择。

这是表格的结构,我是否需要选择所有带有“摩ri座”星座的用户?

可以更改表的结构(如果需要,甚至可以添加新表):

CREATE TABLE IF NOT EXISTS `horoscope` (
    `id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    `name` VARCHAR(255) NOT NULL UNIQUE,
    `date_start` VARCHAR(5),
    `date_end` VARCHAR(5)
);
CREATE INDEX `horoscope_idx_1` ON `horoscope`(`date_start`, `date_end`);

CREATE TABLE IF NOT EXISTS `user` (
    `id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    `name` VARCHAR(255) NOT NULL,
    `birthday` DATE NOT NULL
);

插入测试数据

# Insert horoscope in table
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Aries', '03-21', '04-20');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Taurus', '04-21', '05-20');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Gemini', '05-22', '06-21');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Cancer', '06-22', '07-22');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Leo', '07-23', '08-23');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Virgin', '08-24', '09-22');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Libra', '08-23', '10-22');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Scorpio', '10-23', '11-21');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Sagittarius', '11-22', '12-21');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Capricorn', '12-22', '01-20');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Aquarius', '01-21', '02-19');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Pisces', '02-20', '03-20');

# Insert random user in table
DROP PROCEDURE IF EXISTS `add_user`;
CREATE PROCEDURE `add_user`(IN `count_user` INT)
    LANGUAGE SQL
    DETERMINISTIC
    SQL SECURITY DEFINER
    COMMENT 'A procedure for inserting random user'

BEGIN
    DECLARE i INT DEFAULT (
        SELECT `id`
        FROM `user`
        ORDER BY `id` DESC
        LIMIT 1
    );
    IF i IS NULL
        THEN SET i = 1;
    END IF;

    SET `count_user` = `count_user` + i;

    WHILE i <= `count_user` DO
        SET @`name` = CONCAT('user_', i);
        SET @`user_birth` = '1980-01-01' + INTERVAL (RAND() * 365 * 20) DAY;

        INSERT INTO `user` (`name`, `birthday`) VALUES (@`name`, @`user_birth`);

        SET i = i + 1;
    END WHILE;
END;
CALL `add_user`(1000);
DROP PROCEDURE IF EXISTS `add_user`;

2 个答案:

答案 0 :(得分:0)

我决定=)

SELECT *
FROM user as u
WHERE (
    DATE_FORMAT(u.birthday, '%m%d') >= (
        SELECT
            CONCAT(LEFT(`h`.`date_start`, 2), RIGHT(`h`.`date_start`, 2))
        FROM horoscope h
        WHERE h.name = 'Capricorn'
    ) AND DATE_FORMAT(u.birthday, '%m%d') <= 1231
) OR (
    DATE_FORMAT(u.birthday, '%m%d') >= 101 AND DATE_FORMAT(u.birthday, '%m%d') <= (
        SELECT
            CONCAT(LEFT(`h`.`date_end`, 2), RIGHT(`h`.`date_end`, 2))
        FROM horoscope h
        WHERE h.name = 'Capricorn'
    )
);

答案 1 :(得分:0)

如果每个星座的边界都是固定的日期,那么将出生符号作为属性添加到每个用户将是有意义的,而不是每次您需要该信息时都按日期进行过滤。

但是,如果您需要过滤,我会建议以下内容:

select *
from user u
inner join horoscope h
where (h.date_start > h.date_end 
       and u.birthday between str_to_date(concat(year(u.birthday)-1, h.date_start),'%Y%m-%d')
                          and str_to_date(concat(year(u.birthday), h.date_end),'%Y%m-%d')
   )
or (h.date_start < h.date_end 
    and u.birthday between str_to_date(concat(year(u.birthday), h.date_start),'%Y%m-%d')
                       and str_to_date(concat(year(u.birthday), h.date_end),'%Y%m-%d')
   )

但是请注意,星座中2个varchar(5)列的索引可能对您的查询没有帮助。

请参阅:https://rextester.com/OAOTEH65480