ActiveRecord를 사용하여 FROM 절의 하위 쿼리를 작성하는 방법
19316 단어 SQL루비RailsActiveRecord
JOIN
하고 GROUP BY
만났습니다.SQL이라고 간단하게 쓸 수 있습니다만 ActiveRecord라고 어떻게 써야할지 몰랐기 때문에, 정리합니다.
결론
먼저 서브 쿼리에 상당하는 처리를 ActiveRecord로 기술해 변수에 대입해 두고,
ModelClass.from("(#{subquery.to_sql}) AS sub").select('sub.columnA, sub.columnB')
GROUP BY
메서드를 호출하여 FROM 절의 하위 쿼리로 처리할 수 있습니다.만난 상황
각 테이블은 다음과 같이 되어 있습니다.
요약하면 이런 상황입니다.
SELECT id, restaurant_id, guest_name, reserved_at FROM reservations;
1|1|岩瀬 好近|2019-08-01 13:00:00
2|1|戸田 良市|2019-08-01 14:00:00
3|2|森 信好|2019-08-01 15:00:00
4|2|平山 利次|2019-08-01 11:00:00
5|1|金城 義勝|2019-08-01 18:00:00
6|2|関 知実|2019-08-01 19:00:00
SELECT id, name FROM restaurants;
1|大衆系レストラン
2|高級レストラン
SELECT id, restaurant_id, name FROM courses;
1|1|焼き魚コース
2|1|串カツ三昧
3|1|寿司セット
4|1|コラボピザ
5|2|高級ピッツア
6|2|色とりどりのパスタ
7|2|イタリアンフルコース
SELECT id, restaurant_id, name, category_id FROM courses;
1|1|焼き魚コース|1
2|1|串カツ三昧|1
3|1|寿司セット|1
4|1|コラボピザ|2
5|2|高級ピッツア|2
6|2|色とりどりのパスタ|2
7|2|イタリアンフルコース|2
SELECT id, name FROM categories;
1|和食
2|イタリアン
해결 방법
각 테이블을 JOIN하여
DISTINCT
와 from
를 categories.name
하는 하위 쿼리를 정의합니다. (subquery 변수에 할당)reservations.id
메서드에 subquery를 하위 쿼리로 확장하고 전달하고 SELECT DISTINCT
→ from
를 호출하여 범주별 예약 수를 검색 할 수있었습니다.subquery = Reservation.all
.joins(restaurant: { courses: :category })
.select(%(
distinct categories.name AS category_name,
reservations.id AS reservation_id
))
reservations = Reservation.from("(#{subquery.to_sql}) AS reservations")
.group('reservations.category_name')
.select(%(
reservations.category_name AS category_name,
COUNT(reservations.reservation_id) AS reservation_count
))
reservations.map do|reservation|
[reservation.category_name, reservation.reservation_count]
end
=> [["イタリアン", 6], ["和食", 3]]
(2019/8/21 13:38 추가)
@ j 치토 님이
group
를 사용하는 방법을 코멘트했습니다.확실히, 이쪽이 깨끗이 쓸 수 있습니다. 감사합니다.
Reservation
.joins(restaurant: { courses: :category })
.group('categories.name')
.distinct
.count(:id)
(참고) 하위 쿼리를 사용하지 않고 잘못된 값을 얻은 사례
참고까지 처음 쓴 코드를 노출합니다. 이 코드는 올바른 예약 수를 얻을 수 없습니다.
reservations = Reservation.all
.joins(restaurant: { courses: :category })
.group('categories.name')
.select(%(
categories.name AS category_name,
COUNT(reservations.id) AS reservation_count
))
reservations.map do|reservation|
[reservation.category_name, reservation.reservation_count]
end
=> [["イタリアン", 12], ["和食", 9]]
원인은 GROUP BY하기 직전의 테이블을 참조하면 일목요연합니다.
하나의 레스토랑에 여러 코스가 존재하면 JOIN했을 때 각 레스토랑의 코스 수만큼 레코드가 중복되어 버리는 것이 원인입니다.
SELECT reservations.id,
restaurants.NAME,
courses.NAME,
categories.NAME
FROM "reservations"
INNER JOIN "restaurants"
ON "restaurants"."id" = "reservations"."restaurant_id"
INNER JOIN "courses"
ON "courses"."restaurant_id" = "restaurants"."id"
INNER JOIN "categories"
ON "categories"."id" = "courses"."category_id";
1|大衆系レストラン|焼き魚コース|和食
2|大衆系レストラン|焼き魚コース|和食
5|大衆系レストラン|焼き魚コース|和食
1|大衆系レストラン|串カツ三昧|和食
2|大衆系レストラン|串カツ三昧|和食
5|大衆系レストラン|串カツ三昧|和食
1|大衆系レストラン|寿司セット|和食
2|大衆系レストラン|寿司セット|和食
5|大衆系レストラン|寿司セット|和食
1|大衆系レストラン|コラボピザ|イタリアン
2|大衆系レストラン|コラボピザ|イタリアン
5|大衆系レストラン|コラボピザ|イタリアン
3|高級レストラン|高級ピッツア|イタリアン
4|高級レストラン|高級ピッツア|イタリアン
6|高級レストラン|高級ピッツア|イタリアン
3|高級レストラン|色とりどりのパスタ|イタリアン
4|高級レストラン|色とりどりのパスタ|イタリアン
6|高級レストラン|色とりどりのパスタ|イタリアン
3|高級レストラン|イタリアンフルコース|イタリアン
4|高級レストラン|イタリアンフルコース|イタリアン
6|高級レストラン|イタリアンフルコース|イタリアン
이전 섹션과 같이 하위 쿼리에서
select
한 다음 COUNT(DISTINCT some_column)
하면 중복을 제거한 건수를 얻을 수 있습니다.참고
Reference
이 문제에 관하여(ActiveRecord를 사용하여 FROM 절의 하위 쿼리를 작성하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/Y_uuu/items/558d4a2b8017ef8e2780텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)