programing

왼쪽/오른쪽 조인이 예상대로 null을 반환하지 않음

newstyles 2023. 8. 27. 08:58

왼쪽/오른쪽 조인이 예상대로 null을 반환하지 않음

MariaDB-10.2.6을 사용하고 있습니다.

현재 스키마는 다음과 같습니다.

CREATE TABLE `daily_report` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `date` date DEFAULT NULL,
  `user_id` varchar(255) NOT NULL,
  CONSTRAINT `daily_report_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user` 
  (`id`) ON DELETE SET NULL ON UPDATE CASCADE
)

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `shall_create_every_day` tinyint(1) NOT NULL
)

CREATE TABLE `calendar` (
  `datefield` date
)

규칙:

  1. 의 사용자shall_create_every_day로 설정한.1생성할 것입니다.daily_report매일
  2. 나는 달력 테이블이 있습니다.calendar로부터의 모든 날짜로 구성되어 있습니다.2000-01-01까지2020-12-31(Generate_series는 MySQL/MariaDB에서 사용할 수 없기 때문에)

다음 쿼리를 시도해 보았습니다.

select daily_report.id, daily_report.date, user.id, calendar.datefield
from calendar
left join daily_report on daily_report.date=calendar.datefield
right join user on daily_report.user_id=user.id and user.shall_create_every_day=1
where calendar.datefield='2017-08-02'

데이트 범위를 위해 노력했지만, 테스트 목적으로, 저는where단 하루 전의 진술.

모든 사용자를 반환해야 합니다.shall_create_every_day아무것도 만들어내지 못한daily_report2017-08-12'에서.하지만 저는 그날 생성된 보고서의 조합만 받고 있습니다.

일치하지 않는 행에 대해 null을 반환하는 왼쪽/오른쪽 조인에 대해 제가 오해한 부분이 있습니까?

시리즈 생성은 MariaDB에서 사용할 수 있습니다.여기를 보세요.와 같은 것입니다.

SELECT '2000-01-01' + INTERVAL seq
    FROM seq_0_241

넌 할 수 있다.JOIN실제로 표를 구체화하지 않고 이렇게까지.

섞지 마세요LEFT JOIN그리고.RIGHT JOIN그것이 문제의 원인이거나, 제 머리가 회전하느라 그것을 이해할 수 없을 정도입니다.다음과 같이 해석될 수 있음을 명심하십시오.

FROM a LEFT JOIN (b RIGHT JOIN c)

아마 당신이 원했던 것이 아닐 겁니다어떤 경우에도 괄호는 허용됩니다(그리고 혼합할 때 권장됩니다).LEFT그리고.RIGHT).

절대로 왼쪽과 오른쪽 조인을 결합하지 마십시오. 이것은 단지 혼란스러울 뿐입니다. (글쎄요, 대부분의 사람들은 왼쪽 조인보다 읽기 어렵기 때문에 오른쪽 조인을 전혀 사용하지 않습니다.)

쿼리는 다음을 수행합니다.

  1. 모든 일정관리 레코드를 가져옵니다.
  2. daily_report records(사용 가능한 경우)에 가입합니다. 그렇지 않으면 가입할 빈 더미 레코드를 만듭니다.
  3. shall_create_every_day = 1로 모든 사용자 레코드를 가져옵니다.
  4. 사용 가능한 경우 첫 번째 데이터 세트를 사용자에게 결합하고, 그렇지 않은 경우 빈 더미 레코드를 만들어 사용자에게 결합합니다.
  5. where 절을 적용하여 (4)에서 생성된 모든 외부 조인 레코드를 해제합니다.

그래서 무엇보다도 먼저 스스로에게 물어봐야 합니다. 외부 연결이 필요한가요?당신이 모르는 사용자와 달력에 관해서요.사실 달력에서 원하는 것은 '2017-08-02' 항목이 있는지 확인하는 것뿐입니다.또한 사용자 표에 대해서도 마찬가지입니다. 특정 사용자와 특정 날짜에 대한 모든 보고서를 원할 경우 이는 단순한 기준에 불과합니다.

따라서 보고서 테이블에서 선택하고 해당 보고서가 속한 기준을 다음과 같이 지정합니다.WHERE

select id, date, user_id
from daily_report 
where user_id in (select id from user where shall_create_every_day = 1)
and date = (select datefield from calendar where datefield = '20170802');

누락된 보고서를 포함한 보고서가 있는 날짜와 사용자를 표시하려면 일정관리와 사용자를 교차 가입시키고 보고서에 왼쪽으로 가입시킵니다.

select r.id, c.datefield, u.id as user_id
from (select id from user where shall_create_every_day = 1) u
cross join (select datefield from calendar where datefield = '20170802') c
left join daily_report r on r.user_id = u.id and r.date = c.datefield;

당신은 당신의 질문을 다소 복잡한 방식으로 표현했습니다.저는 이것을 왼쪽으로 표현하고 싶습니다.user각 사용자의 보고서에 대한 항목을 포함하는 두 번째 테이블에 대한 각 날짜의 테이블.작성하지 않은 사용자의 특징은 주어진 사용자 레코드가 이 두 번째 표의 어떤 것과도 일치하지 않는다는 것입니다.

select
    u.id
from user u
left join
(
    select
        c.datefield,
        dr.me_id
    from calendar c
    left join daily_report dr
        on dr.date = c.datefield
    where c.datefield = '2017-08-02'
 ) cal
    on cal.me_id = u.id and
       u.shall_create_every_day = 1
where
    cal.me_id is null;

이런 식으로 할 수 있습니다.

SELECT * 
FROM daily_report 
RIGHT JOIN (calendar c,user u) ON user_id=u.id AND date=c.datefield 
WHERE c.datefield='2017-08-02' AND u.shall_create_every_day=1

추신: 테이블 구조에 오류가 있는 것 같습니다.daily_report.user_id야 .intvarchar.

언급URL : https://stackoverflow.com/questions/46049620/left-right-joins-not-returning-nulls-as-expected