1965. Employees With Missing Information

이번 문제는 많이 새로웠다,  두 테이블 데이터 사이에 비어있는 아이디를 출력해야한다. 난해하다... 셀렉트 따로따로 하라그러면 하겠는데 두가지 문제의 2조건을 모두 충족할려면 셀렉트를 두번해야하지 않겠는가 ....머리가 터질듯이 아파왔다.. ㅠ
아래 관련토픽 에서 유니온 이라는 태그를 보고 검색했다.
'union'
두개이상 의 SELECT 결과를 합칠수 있습니다.  합친 결과에서 중복되는 행은 하나만 표시합니다.

단, 컬럼의 개수가 같아야하고, 각 컬럼의 데이터타입이 같아야합니다.

테이블 수십개도 유니온으로 가능한가 ? 가능하다.ㅋㅋㅋ 칼럼의 개수와 데이터 타입만 일치한다면 뭐 마음껏 써도 된다.

단 중복된 데이터를 원한다면 union all 이라는 구조를 이용해서 작성해 주어야 한다.

union all 에 대한 예제를 검색하다 재미난 문구를 발견했다.

만약 테이블 안에서 유니크 한 값을 반환한다면 union all 을 이용하는게 더 빠른 결과를 반환한다는 내용이다.
우리의 경우 각각 의 테이블에서 이름 과 급여를 놓친 부분을 반환을 하는데 있어 union all 이 될까 싶었지만 된다.
뭐 안되더라도 위에 문구 처럼 결과에 DISTINCT 를 넣어주면 되지 않은가 싶다.

select e.employee_id as employee_id from Employees e
left join Salaries s
on s.employee_id = e.employee_id
where s.employee_id is null
union all
select s.employee_id as employee_id from Employees e
right join Salaries s
on s.employee_id = e.employee_id
where e.employee_id is null
order by employee_id;

정말 단순하다.. select 두개 사이에 유니온 써주면 된다.. 호올리... 단순하게 설명하자면
left join 을 이용해 데이터를 한군데 전부 몰아주자. 여기서 join 으로 구사한다면 원하는 데이터를 얻지못한다. 양쪽 모두에 속해 있는 결과만 리턴받기 때문에.. left join 을 써주어야한다.

뭐 이것만 안다면 밑에 셀렉트 문도 크게 다를바 없다. 

추가적으로 union 이나 union all 이나 그렇게 큰 속도차이는 없었다. 각각 990ms 900ms 정도 만약 릿코드에 나온 데이터들 보다 큰 데이터를 다루게 된다면 이러한 조그마한 속도의 디테일 이 나중에 더 큰 나비효과 를 불러 일으킬수 있다고 생각한다. 기억해두자 union all 생각보다 많이 쓸것같다.

 

1795. Rearrange Products Table

보고나서 바로 유니온 떠올랐다....

각 가게 별로 찾아서 값을 넣어주면 되는게 아닌가 ?
왜냐하면 이미 가게의 종류가 칼럼안에 정의가 되어있기 때문에 이렇게 생각했다. 
위에서 유니온 테이블 2개이상 가능하다고 했으니 바로 해보자 

select product_id,"store1" as store, store1 as price
from products
where store1 is not null
union all
select product_id,"store2" as store, store2 as price
from products
where store2 is not null
union all
select product_id,"store3" as store, store3 as price
from products
where store3 is not null;

output 출력에 맞게 select 설정해주고 각 스토어 별로 눌이 아닌경우를 찾아서 뽑아주면 된다. ㅋㅋㅋ 위에서 하고 오니 뭔가좀더 쉽다. 

 

608. Tree Node

음... 트리를 알고리즘 에서 만 보던게 여기서 보니 새롭지만 문제 넘기고싶다. 전혀 읽고 싶지가 않다...

첫번쨰 미디움 난이도의 문제 이다. 

id 는 본인 자신의 숫자를 의미하고, p_id 는 자신보다 상위 노드의 트리 아이디를 가르킨다. 항상 트리의 형태가 가능한 숫자들만 주어진다고 한다. 

여기서 root 와 inner leaf 를 구분해서 작성해 주어야 한다. 트리가 나와서 그렇지 맨위 root 중간 inner leaf 꼬리 로 분류해서 작성해주면 별볼일 없는 문제다. 여기서 inner 의 체크가 중요한데 이거는 p_id 의 대상이 2개 라면 그 p_id 본인은 inner 가된다 위의 두경우를 제외 한다면 나머지는 leaf 때려주면 된다.셀렉트 3개 유니온 갈겨주자. 물론 각 노드들은 유니크한 값들이니 위에서 배운대로 union all 을하자.

 

약 4번 제출하고 통과한 코드이다. 일련의 과정을 적을 예정이니 답이 궁금하면 스크롤 내려서 확인바란다.

 제출 1번

# Write your MySQL query statement below
select id,"Root" as type from tree
where p_id is null
union all
select id,"Inner" as type from tree
where id in (select p_id from tree where p_id != 1)
union all
select id,"Leaf" as type from tree
where id not in (select p_id from tree where p_id is not null);

null 인 아이디 라면 ? 그게 root 이다 부모가 없으니깐(???), inner 의 경우는 ? 1 이 부모가 아닌 경우 를 서브쿼리로 뽑아 in 으로 확인후 inner 로 퍼올린다, 마지막 inner 와 동일 조건으로 not in 을 이용해 주었다.


실패했다... ㅋㅋㅋ 

16/19 에서 걸린다. {"headers": {"Tree": ["id", "p_id"]}, "rows": {"Tree": [[1,null]]}} 이경우 나는 leaft 1 이 다시 들어간다 왜 ?

id 에는 null 을 포함한 값들을 가지고 대조하는데 내가 퍼올린건 null 이 아닌 값들이 올라온다.  그래서 leaf 1 도 들어간다 and 연산으로 이어붙여주자.

# 수정부분
select id,"Leaf" as type from tree
where id not in (select p_id from tree where p_id is not null) and p_id is not null;

아씨 17/19 에서 걸린다 왜? root가 1이 아닌 경우가 있다..... 문제 어디에서도 1 이 항상 루트인 경우라는 말은 없었다.... 다시 고쳐주자

#수정부분
select id,"Inner" as type from tree
where id in (select p_id from tree where p_id is not null)

응 ? 이러고 제출하니 1번이 틀린다 왜 ? 1번 제출과 동일한 이유다 null 이아닌값을 퍼올리고 null 값을 들고 대조하니 당연히 중복이지..

#코드최종
select id,"Root" as type from tree
where p_id is null
union
select id,"Inner" as type from tree
where id in (select p_id from tree where p_id is not null) and p_id is not null
union
select id,"Leaf" as type from tree
where id not in (select p_id from tree where p_id is not null) and p_id is not null
order by id;

아 union all 을 이용해서 작성해도 통과된다. 위에설명한것과 같이 각 select 문은 유니크한 값들 만 리턴한다.

아유... 드디어 통과 됬다... 멀리도 돌아왔다.... 이건 디스커스 를 안볼수가 없다 보러가보자.

SELECT id,
CASE
    WHEN p_id is NULL THEN "Root"
    WHEN id NOT IN (SELECT p_id FROM Tree WHERE p_id IS NOT NULL) THEN "Leaf"
    ELSE "Inner" 
END AS type 
FROM Tree

하 씨 ? case 와 if 문을 사용할수 있는건 알고 있었다. 그런데 여기에 이렇게 활용할 생각을 1도 생각 못했다. 와.....

이사람은 뒤에 and is not null 을 또 안써도 되는이유는 for 문처럼 하나씩 들어오는데 root 의 경우 이미 위에서 걸러지기 떄문에.. 하 씨 와 ..... 멋진 코드다 내 union  코드보다 3000배 간결하고 가독성도 좋다..

오늘 은 할당량이 좀 많다. 4문제다 .. 마지막 문제 보고 가자.

 

문제는 진짜 간단하다. 2번째 높은 급여를 반환 하는 문제이다. 자바 Pq 만들어서 쓱삭 할텐데 아쉽다. 그런데 왼걸 정말 난해했다 구현하는데 있어 제출 횟수가 보이는가.... 고생 많이한 문제다..

 

어떻게 해야 두번째 높은 값을 뽑을 수 있는가 ? 느낌이 1도 안와서 스터디원(큐빈) 에게 물어 봤다. limit 과 offset 을 이용해서 짜르면 어떻냐는 제안을 받았고 바로 제출.

select 
	salary as "SecondHighestSalary"
from employee
order by salary desc
limit 1 offset 1;

음 ? null 처리 가 안되어있다. if 문으로 처리해주자.

select 
	if(salary = null ,null,salary) as "SecondHighestSalary"
#중략----

아니 ? null 값이 반영이 안된다.  null 이 되어서 아예 반영이 안되는듯 싶었다.

case 를 이용해보자..

select 
	case
        when salary is not null then salary
        else (null)
    end as SecondHighestSalary
# 중략 ----

하씨 ? null 이 반영이 안된다.  mysql 로컬 서버를 키고 이것저것 실험 을 했다. null 자체 스트링으로 반환을 하니 응 ? 모든 반환값들이 문자열로 변했다. cast 를 이용해 형변환을 salary 에 int 로 했지만 안된다. case 를 이용하면 오로지 하나의 데이터 타입 만을 반환하는것 같았다. 

select 
	case
        when count(*)<2 then null
        else cast(min(salary) as decimal)
    end as SecondHighestSalary
from (
    select distinct salary 
    from employee 
    order by salary 
    Desc Limit 2
) a

이건 통과된 코드이다. 내코드와의 차이 점이라면 from 에서 퍼올린 데이터 기준으로 셀렉트 값이 나간다. 어떤 차이가 있는것인가.. 

select 
	salary
from employee
order by salary desc
limit 1 offset 1;

이렇게 특별하게 지정이 된다면 빈값을 반환한다. 이게 문제다 ㅋㅋ ..... limit1 offset1 아무데이터도 없다면 아무것도 반환하지 않는다.. null 조차... 에초에 전제 자체가 잘못된것이다.

select case 
when count(Salary) > 1 then (select distinct Salary from Employee
    order by Salary DESC limit 1, 1) 
else NULL end
from Employee;

내가 구현하고자 했던 코드가 이런 코드 였는데 많이 돌아간것 같다.

 

max 를 이용한 간단한 풀이를 보자.

Select MAX(salary) as SecondHighestSalary 
from Employee 
where salary < (select MAX(salary) from Employee);

max 를 이용하면 null 처리도 간단하게 할수 있다. max 값이 없다면 null 을 리턴해주기 때문에 이런 방식의 코드가 가능하다.

max 를 두번이용해서 2번째 값을 찾아주는것이 참 생소했다. ㅎㅎ......

 

와 오늘 sql 은 풀이도 오래걸리고 블로그 작성도 오래걸렸다...

확실히 모르는 부분은 디스커스 를 보면서 내꺼화 시켜야 하는데 그게 참 어려운 부분이다.

+ Recent posts