简体   繁体   中英

SQL UNION not working with 2 HAVING clauses

I want to use UNION to join two SQL SELECT queries. I need the final data to use the HAVING clause to filter the entire query. Here is my statement:

SELECT CLIENT, 
       BIZNAME, 
       BIZSTREET, 
       BIZCITY, 
       BIZSTATE, 
       BIZZIP, 
       BIZPHONE, 
       URL, 
       LAT, 
       LNG, 
       CONSOLIDATED, 
       ( 3959 * ACOS(COS(RADIANS('%s')) * COS(RADIANS(LAT)) * COS( 
                     RADIANS(LNG) - RADIANS('%s')) 
                              + SIN 
                              (RADIANS('%s')) * SIN(RADIANS(LAT))) ) AS distance 
FROM   BizInfo 
       INNER JOIN WebSites 
               ON WebSites.CUSTOMER = BizInfo.CUSTOMER 
WHERE  BizInfo.CLIENT = 'GCB' 
       AND WebSites.STATUS <> 'Cancel' 
       AND WebSites.STATUS <> 'In Progress' 
       AND WebSites.STATUS <> 'Review' 
       AND WebSites.STATUS <> 'Testing' 
UNION 
SELECT CLIENT, 
       BIZNAME, 
       BIZSTREET, 
       BIZCITY, 
       BIZSTATE, 
       BIZZIP, 
       BIZPHONE, 
       'http://www.abc-site.com', 
       LAT, 
       LNG, 
       '0', 
       ( 3959 * ACOS(COS(RADIANS('%s')) * COS(RADIANS(LAT)) * COS( 
                     RADIANS(LNG) - RADIANS('%s')) 
                              + SIN 
                              (RADIANS('%s')) * SIN(RADIANS(LAT))) ) AS distance 
FROM   BizInfo 
WHERE  CLIENT = 'GCB' 
       AND BIZNAME = 'Acme' 
HAVING DISTANCE < '%s' 
ORDER  BY DISTANCE 
LIMIT 0, 200 

I read on this site http://www.really-fine.com/SQL_union.html (GROUP BY and HAVING clauses can be used only within individual queries and cannot be used to affect the final results set. ), but I don't understand how to implement this or if it is correct.

How do I properly write this SQL query?

HAVING can only be used in an aggregate query with a GROUP BY clause. Your queries do not. Use WHERE instead.

  1. Those are scalar functions, not aggregate functions. So to filter on the result, use the WHERE clause, not the HAVING clause. You are filtering horizontally, not vertically.

  2. You cannot use a column alias in the WHERE clause, so you have to restate the functions used in the SELECT list (I've done that in the query below).

Try the following. There are 2 issues at play.

SELECT Client,
       BizName,
       BizStreet,
       BizCity,
       BizState,
       BizZip,
       BizPhone,
       url,
       lat,
       lng,
       Consolidated,
       (3959 * acos(cos(radians('%s')) * cos(radians(lat)) *
                    cos(radians(lng) - radians('%s')) +
                    sin(radians('%s')) * sin(radians(lat)))) AS distance
  FROM BizInfo
 INNER JOIN WebSites
    ON WebSites.Customer = BizInfo.Customer
 WHERE BizInfo.Client = 'GCB'
   AND WebSites.Status <> 'Cancel'
   AND WebSites.Status <> 'In Progress'
   AND WebSites.Status <> 'Review'
   AND WebSites.Status <> 'Testing'
UNION
SELECT Client,
       BizName,
       BizStreet,
       BizCity,
       BizState,
       BizZip,
       BizPhone,
       'http://www.abc-site.com',
       lat,
       lng,
       '0',
       (3959 * acos(cos(radians('%s')) * cos(radians(lat)) *
                    cos(radians(lng) - radians('%s')) +
                    sin(radians('%s')) * sin(radians(lat)))) AS distance
  FROM BizInfo
 WHERE Client = 'GCB'
   AND BizName = 'Acme'
   and (3959 * acos(cos(radians('%s')) * cos(radians(lat)) *
                    cos(radians(lng) - radians('%s')) +
                    sin(radians('%s')) * sin(radians(lat)))) < '%s'
 ORDER BY distance LIMIT 0, 200

You can probably solve that very easily by wrapping everything into a subquery. Something like :

SELECT
  *
FROM
  (
      SELECT Client, BizName, BizStreet, BizCity, BizState, BizZip, BizPhone, url, lat, lng, Consolidated,
      ( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) )
      AS distance FROM BizInfo
      INNER JOIN WebSites ON WebSites.Customer = BizInfo.Customer
      WHERE BizInfo.Client = 'GCB'
      AND WebSites.Status <> 'Cancel' AND WebSites.Status <> 'In Progress' AND WebSites.Status <> 'Review' AND WebSites.Status <> 'Testing' 
      UNION SELECT Client, BizName, BizStreet, BizCity, BizState, BizZip, BizPhone, 'http://www.abc-site.com', lat, lng, '0', 
      ( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) )
      AS distance FROM BizInfo WHERE Client = 'GCB' AND BizName = 'Acme'
  ) AS ClientInfo
WHERE 
  distance < '%s' 
ORDER BY 
  distance 
LIMIT 0 , 200

This is the fastest path to what you want but it is not very clean.

Also please tell me that all those parameters are not vulnerable to SQL injection ...?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM