0

私は選択を行っているところから多くのテーブルを持っていますが、重要な部分についてのみ書きます。私は2つのテーブルを持っています

宿泊施設:

id | title | desc | etc..

宿泊施設の部屋:

id | accomodation_id | beds | rooms

次に、フィルタリングするまで、どれがうまく機能するかを長い間選択し、ベッド数(ベッド*部屋)に宿泊施設があります。乗算を使用してテーブル accomodation_rooms から単純な選択を試みると、うまく機能します。したがって、問題は他のテーブルに参加する場所にあるはずです。

これは私の選択です:

SELECT 
  accomodation.*, 
  db_cities.title_en AS city, 
  db_cities.title_url AS city_url, 
  db_countries.title_url_en AS country_url, 
  SUM(accomodation_rooms.beds * accomodation_rooms.rooms) AS total_persons 
FROM 
  (SELECT id, aid, title_en, title_url_en, address, city_id, zip, district_id, province_id, region_id, country_id, mountain_id, stars, latitude, longitude, picture, valid_from, valid_to 
  FROM accomodation 
  ORDER BY info_date_add DESC) 
    AS accomodation 
LEFT JOIN db_cities 
  ON db_cities.id = accomodation.city_id 
JOIN db_countries 
  ON db_countries.id = accomodation.country_id 
JOIN skiresort_locations 
  ON 
    (((acos(sin((skiresort_locations.latitude*pi()/180)) * 
    sin((accomodation.latitude*pi()/180)) + 
    cos((skiresort_locations.latitude*pi()/180)) * 
    cos((accomodation.latitude*pi()/180)) * 
    cos(((skiresort_locations.longitude - 
    accomodation.longitude)*
    pi()/180))))*180/pi())*60*1.1515*1.609344) 
      < '50' 
JOIN accomodation_rooms 
  ON accomodation_rooms.accomodation_id = accomodation.id 
WHERE 
  db_countries.title_url_en LIKE '%country_title%' AND 
  accomodation.region_id = '8' 
GROUP BY 
  accomodation.aid 
HAVING 
  total_persons >= '1' 
ORDER BY CASE 
  WHEN 
    accomodation.valid_to>=NOW() AND 
    accomodation.valid_from<=NOW() 
      THEN 0 
  WHEN 
    NOW()>accomodation.valid_to AND 
    accomodation.valid_to!='0000-00-00' 
      THEN 1 
  ELSE 2 
    END, 
  accomodation.title_en 
LIMIT 10 
OFFSET 0

total_persons は 13 を返すはずですが、624 を返しますが、その理由がよくわかりません。

4

2 に答える 2

1

副選択を使用して、必要な数量を取得するのがおそらく最善であると考えてください。

accomodation_rooms は、その場所にあるベッドの各数の数 (つまり、1 x 5 ベッドの部屋、2 x 3 ベッド、5 x 2 ベッド) を示すいくつかの宿泊施設の複数の行を格納するテーブルであると仮定します。

SELECT 
  accomodation.*, 
  db_cities.title_en AS city, 
  db_cities.title_url AS city_url, 
  db_countries.title_url_en AS country_url, 
  accomodation_rooms.total_persons 
FROM 
  (SELECT id, aid, title_en, title_url_en, address, city_id, zip, district_id, province_id, region_id, country_id, mountain_id, stars, latitude, longitude, picture, valid_from, valid_to 
  FROM accomodation 
  ORDER BY info_date_add DESC) 
    AS accomodation 
LEFT JOIN db_cities 
  ON db_cities.id = accomodation.city_id 
JOIN db_countries 
  ON db_countries.id = accomodation.country_id 
JOIN skiresort_locations 
  ON 
    (((acos(sin((skiresort_locations.latitude*pi()/180)) * 
    sin((accomodation.latitude*pi()/180)) + 
    cos((skiresort_locations.latitude*pi()/180)) * 
    cos((accomodation.latitude*pi()/180)) * 
    cos(((skiresort_locations.longitude - 
    accomodation.longitude)*
    pi()/180))))*180/pi())*60*1.1515*1.609344) 
      < '50' 
INNER JOIN (SELECT accomodation_id, SUM(accomodation_rooms.beds * accomodation_rooms.rooms) AS total_persons FROM accomodation_rooms GROUP BY accomodation_id) accomodation_rooms
  ON accomodation_rooms.accomodation_id = accomodation.id 
  AND accomodation_rooms.total_persons >= 1
WHERE db_countries.title_url_en LIKE '%country_title%' 
AND accomodation.region_id = '8' 
ORDER BY CASE 
  WHEN accomodation.valid_to>=NOW() AND accomodation.valid_from<=NOW() 
      THEN 0 
  WHEN NOW()>accomodation.valid_to AND accomodation.valid_to!='0000-00-00' 
      THEN 1 
  ELSE 2 
    END, 
  accomodation.title_en 
LIMIT 10 
OFFSET 0

マイナーな点として、サブ選択として宿泊施設の元の選択が必要かどうかはわかりません (または order by 句がありますが、その中に制限があるようには見えないので、影響はないと思います)。 :-

SELECT 
  accomodation.id, 
  accomodation.aid, 
  accomodation.title_en, 
  accomodation.title_url_en, 
  accomodation.address, 
  accomodation.city_id, 
  accomodation.zip, 
  accomodation.district_id, 
  accomodation.province_id, 
  accomodation.region_id, 
  accomodation.country_id, 
  accomodation.mountain_id, 
  accomodation.stars, 
  accomodation.latitude, 
  accomodation.longitude, 
  accomodation.picture, 
  accomodation.valid_from, 
  accomodation.valid_to, 
  db_cities.title_en AS city, 
  db_cities.title_url AS city_url, 
  db_countries.title_url_en AS country_url, 
  accomodation_rooms.total_persons 
FROM accomodation
LEFT JOIN db_cities 
  ON db_cities.id = accomodation.city_id 
JOIN db_countries 
  ON db_countries.id = accomodation.country_id 
JOIN skiresort_locations 
  ON 
    (((acos(sin((skiresort_locations.latitude*pi()/180)) * 
    sin((accomodation.latitude*pi()/180)) + 
    cos((skiresort_locations.latitude*pi()/180)) * 
    cos((accomodation.latitude*pi()/180)) * 
    cos(((skiresort_locations.longitude - 
    accomodation.longitude)*
    pi()/180))))*180/pi())*60*1.1515*1.609344) 
      < '50' 
INNER JOIN (SELECT accomodation_id, SUM(accomodation_rooms.beds * accomodation_rooms.rooms) AS total_persons FROM accomodation_rooms GROUP BY accomodation_id) accomodation_rooms
  ON accomodation_rooms.accomodation_id = accomodation.id 
  AND accomodation_rooms.total_persons >= 1
WHERE db_countries.title_url_en LIKE '%country_title%' 
AND accomodation.region_id = '8' 
ORDER BY CASE 
  WHEN accomodation.valid_to>=NOW() AND accomodation.valid_from<=NOW() 
      THEN 0 
  WHEN NOW()>accomodation.valid_to AND accomodation.valid_to!='0000-00-00' 
      THEN 1 
  ELSE 2 
    END, 
  accomodation.title_en 
LIMIT 10 OFFSET 0

編集 - 各エイドの最新の宿泊記録を取得し、それを結合して残りの最新の宿泊記録を取得するように変更しました。

SELECT 
  accomodation.*, 
  db_cities.title_en AS city, 
  db_cities.title_url AS city_url, 
  db_countries.title_url_en AS country_url, 
  accomodation_rooms.total_persons 
FROM (SELECT aid, MAX(info_date_add) AS max_info_date_add FROM accomodation GROUP BY aid) accomodation_max
INNER JOIN accomodation ON accomodation_max.aid = accomodation.aid AND accomodation_max.max_info_date_add = accomodation.info_date_add
LEFT JOIN db_cities ON db_cities.id = accomodation.city_id 
JOIN db_countries ON db_countries.id = accomodation.country_id 
JOIN skiresort_locations 
  ON 
    (((acos(sin((skiresort_locations.latitude*pi()/180)) * 
    sin((accomodation.latitude*pi()/180)) + 
    cos((skiresort_locations.latitude*pi()/180)) * 
    cos((accomodation.latitude*pi()/180)) * 
    cos(((skiresort_locations.longitude - 
    accomodation.longitude)*
    pi()/180))))*180/pi())*60*1.1515*1.609344) 
      < '50' 
INNER JOIN (SELECT accomodation_id, SUM(accomodation_rooms.beds * accomodation_rooms.rooms) AS total_persons FROM accomodation_rooms GROUP BY accomodation_id) accomodation_rooms
ON accomodation_rooms.accomodation_id = accomodation.id AND accomodation_rooms.total_persons >= 1
WHERE db_countries.title_url_en LIKE '%country_title%' 
AND accomodation.region_id = '8' 
ORDER BY CASE 
  WHEN accomodation.valid_to>=NOW() AND accomodation.valid_from<=NOW() 
      THEN 0 
  WHEN NOW()>accomodation.valid_to AND accomodation.valid_to!='0000-00-00' 
      THEN 1 
  ELSE 2 
    END, 
  accomodation.title_en 
LIMIT 10 
OFFSET 0

編集 - GROUP BY 句を使用して距離の MIN を追加します。ただし、これが DISTINCT を使用するよりもはるかに高速になるかどうかはわかりません。JOIN で多くの計算が必要になります (つまり、宿泊施設に 100 件のレコードがあり、skiresort_locations に 100 件のレコードがある場合、距離を決定するために 10000 件の合理的な複雑な計算が必要になります。計算を行うと、かなりの時間を節約できます (たとえば、少し非正規化しますが、region_id の宿泊施設に結合する地域テーブルがあり、その地域の最小および最大緯度と経度が含まれている可能性があります)。代わりに、複雑な計算を WHERE 句に入れます。また、db_counties の LIKE 句もあります。

SELECT 
  accomodation.*, 
  db_cities.title_en AS city, 
  db_cities.title_url AS city_url, 
  db_countries.title_url_en AS country_url, 
  accomodation_rooms.total_persons,
  MIN(((acos(sin((skiresort_locations.latitude*pi()/180)) * 
    sin((accomodation.latitude*pi()/180)) + 
    cos((skiresort_locations.latitude*pi()/180)) * 
    cos((accomodation.latitude*pi()/180)) * 
    cos(((skiresort_locations.longitude - 
    accomodation.longitude)*
    pi()/180))))*180/pi())*60*1.1515*1.609344)
FROM (SELECT aid, MAX(info_date_add) AS max_info_date_add FROM accomodation GROUP BY aid) accomodation_max
INNER JOIN accomodation ON accomodation_max.aid = accomodation.aid AND accomodation_max.max_info_date_add = accomodation.info_date_add
LEFT JOIN db_cities ON db_cities.id = accomodation.city_id 
JOIN db_countries ON db_countries.id = accomodation.country_id 
JOIN skiresort_locations 
  ON 
    (((acos(sin((skiresort_locations.latitude*pi()/180)) * 
    sin((accomodation.latitude*pi()/180)) + 
    cos((skiresort_locations.latitude*pi()/180)) * 
    cos((accomodation.latitude*pi()/180)) * 
    cos(((skiresort_locations.longitude - 
    accomodation.longitude)*
    pi()/180))))*180/pi())*60*1.1515*1.609344) 
      < '50' 
INNER JOIN (SELECT accomodation_id, SUM(accomodation_rooms.beds * accomodation_rooms.rooms) AS total_persons FROM accomodation_rooms GROUP BY accomodation_id) accomodation_rooms
ON accomodation_rooms.accomodation_id = accomodation.id AND accomodation_rooms.total_persons >= 1
WHERE db_countries.title_url_en LIKE '%country_title%' 
AND accomodation.region_id = '8' 
GROUP BY accomodation.id, 
  db_cities.title_en, 
  db_cities.title_url, 
  db_countries.title_url, 
  accomodation_rooms.total_persons
ORDER BY CASE 
  WHEN accomodation.valid_to>=NOW() AND accomodation.valid_from<=NOW() 
      THEN 0 
  WHEN NOW()>accomodation.valid_to AND accomodation.valid_to!='0000-00-00' 
      THEN 1 
  ELSE 2 
    END, 
  accomodation.title_en 
LIMIT 10 
OFFSET 0
于 2013-06-20T13:27:28.997 に答える
1

新しい要件についてさらに返信します。

その宿泊施設の都市の詳細を取得するには、見つかった宿泊施設から都市テーブルに再度参加する必要があります。

SELECT 
   accomodation.id, 
   accomodation.aid,
   accomodation.title_$lang, 
   accomodation.title_url_$lang,
   accomodation.address,
   accomodation.zip, 
   accomodation.stars, 
   accomodation.picture, 
   accomodation.valid_from, 
   accomodation.valid_to, 
   de_cities_accomodation.title_$lang AS city,
   de_cities_accomodation.title_url AS city_url, 
   db_countries.title_url_$lang AS country_url
FROM  db_cities 
INNER JOIN accomodation 
   ON 
   ( 
      db_cities.id = accomodation.city_id 
      OR 
      (((acos(sin((db_cities.latitude*pi()/180)) * sin((accomodation.latitude*pi()/180)) + cos((db_cities.latitude*pi()/180)) * cos((accomodation.latitude*pi()/180)) * cos(((db_cities.longitude - accomodation.longitude)*pi()/180))))*180/pi())*60*1.1515*1.609344) < '20' ) 
INNER JOIN (SELECT aid, MAX(info_date_add) AS max_info_date_add FROM accomodation GROUP BY aid) accomodation_max 
   ON 
      accomodation_max.aid = accomodation.aid AND 
      accomodation_max.max_info_date_add = accomodation.info_date_add 
LEFT JOIN db_cities de_cities_accomodation
   ON de_cities_accomodation.id = accomodation.city_id 
JOIN db_countries 
   ON db_countries.id = accomodation.country_id 
WHERE 
   db_countries.title_url_en LIKE '%country%' AND 
   db_cities.title_url LIKE '%city%' AND 
   db_cities.id = '1258' 
GROUP BY accomodation.aid 
ORDER BY 
   CASE 
      WHEN accomodation.valid_to>=NOW() AND accomodation.valid_from<=NOW() THEN 0 
     WHEN NOW()>accomodation.valid_to AND accomodation.valid_to!='0000-00-00' THEN 1 
   ELSE 2 END
于 2013-07-01T15:29:54.133 に答える