开发者

Best way to search two queries and eliminate rows without a relationship

I am working on a property website and have record sets for property and for unit, unit has a one-to-many relationship with property. What I'm trying to figure out is how to best create a search function which will output results based on criteria from both. So if I search for a property with the location Manchester and a unit with a freehold tenure I'd like to eliminate all properties which don't have a unit with the tenure of freehold.

A potential solution I've considered is to create a record set for properties which match the property criteria and then create a unit record set for units which match the unit criteria and then finally loop through the property record set in server-side code and eliminate any properties which aren't related to any of the units in the unit record set. Really not sure if this is the best way to do things though so would be keen to hear any suggestions?

Thanks

EDIT (Added table structure and MySQL):

--
-- Table structure for table `property`
--

CREATE TABLE IF NOT EXISTS `property` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` text NOT NULL,
  `street` text NOT NULL,
  `town` text NOT NULL,
  `postcode` text NOT NULL,
  `description` longtext NOT NULL,
  `team_member` varchar(255) NOT NULL DEFAULT '',
  `pdf` text NOT NULL,
  `default_image_id` int(11) DEFAULT NULL,
  `virtual_tour_link` text NOT NULL,
  `date` date NOT NULL DEFAULT '0000-00-00',
  `archive` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='' AUTO_INCREMENT=13 ;

--
-- Table structure for table `unit`
--

CREATE TABLE IF NOT EXISTS `unit` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` text NOT NULL,
  `description` text NOT NULL,
  `size_sq_ft` int(11) DEFAULT NULL,
  `size_acres` float DEFAULT NULL,
  `price` float DEFAULT NULL,
  `rental_price` float DEFAULT NULL,
  `on_application` tinyint(1) DEFAULT NULL,
  UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Stores data for property units' AUTO_INCREMENT=5;

--
-- Table structure for table `property_to_unit`
--

CREATE TABLE IF NOT EXISTS `property_to_unit` (
  `property_id` int(11) NOT NULL,
  `unit_id` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


--
-- MySQL which produces list of properties
--

SELECT
    P.id AS id,
    P.name AS name,
    P.street AS street,
    P.town AS town,  
    P.postcode AS postcode,  
    P.description AS description,
    P.team_member AS team_member,
    P.pdf AS pdf,
    P.virtual_tour_link AS virtual_tour_link,
    P.date AS date,
    P.archive AS archive,
    PI.name as image,
    P2.image_ids as image_ids,
    L2.location_ids as location_ids,
    U2.unit_ids as unit_ids

FROM property P

-- Get default image and join using property id

LEFT JOIN property_image PI ON PI.id = P.default_image_id

-- Create a list of image_ids from property_image and
-- property_to_property_image tables then join using property_id

LEFT JOIN (

 开发者_开发百科   SELECT
        property_id,
        GROUP_CONCAT(CAST(id AS CHAR)) as image_ids
    FROM property_to_property_image PTPI
    LEFT JOIN property_image PI ON PI.id = PTPI.property_image_id
    GROUP BY property_id

) P2 ON P2.property_id = P.id

-- Create a list of locations from property_location table
-- and join using property_id

LEFT JOIN (
    SELECT
        property_id,
        property_location_id,
        GROUP_CONCAT(CAST(property_location.id AS CHAR)) AS location_ids
    FROM property_to_property_location
    INNER JOIN property_location ON property_location.id = property_to_property_location.property_location_id
    GROUP BY property_id
) L2 ON L2.property_id = P.id

-- Create a list of units from unit table
-- and join using property_id

LEFT JOIN (
    SELECT
        property_id,
        unit_id,
        GROUP_CONCAT(CAST(unit_id AS CHAR)) AS unit_ids
    FROM property_to_unit
    INNER JOIN unit ON unit.id = property_to_unit.unit_id
    GROUP BY property_id
) U2 ON U2.property_id = P.id

--
-- MySQL which produces list of units
--

SELECT 
id,
name,
description,
size_sq_ft,
size_acres,
price,
rental_price,
on_application,
tenure_ids,
tenure_names,
type_ids,
type_names
FROM unit AS U

-- join tenure ids and names

LEFT JOIN (

    SELECT
        unit_id,
        GROUP_CONCAT( CAST(UT.id AS CHAR) ) AS tenure_ids,
        GROUP_CONCAT(UT.name) AS tenure_names
    FROM unit_to_unit_tenure UTUT
    INNER JOIN unit_tenure UT ON UT.id = UTUT.unit_tenure_id
    GROUP BY unit_id

) UT ON UT.unit_id = U.id

-- join type ids and names

LEFT JOIN (

    SELECT
        unit_id,
        GROUP_CONCAT( CAST(UTYPE.id AS CHAR) ) AS type_ids,
        GROUP_CONCAT(UTYPE.name) AS type_names
    FROM unit_to_unit_type UTUT
    INNER JOIN unit_type UTYPE ON UTYPE.id = UTUT.unit_type_id
    GROUP BY unit_id

) UTYPE ON UTYPE.unit_id = U.id

WHERE 0=0

I'm currently using a dynamically created WHERE statement appended to each MySQL query to filter the property and unit results.


You're making it a bit more complicated than it is. If I understand correctly, you can easily do this in a single query. This would search properties that have units with a particlar unit tenure id:

select * 
from property p 
where p.id in (
    select pu.property_id
    from property_to_unit pu
        inner join unit u ON pu.unit_id = u.id
        inner join unit_to_unit_tenure uut ON u.id = uut.unit_id
    where uut.id = <cfqueryparam value="#uutid#">
)

Using two queries and then looping through to cross-check sounds like it could be dog slow.


Your situation requires a posted foreign key in the property table. Store the unit_id in the property table and use a join in your query such as:

select * from property p, unit u
where p.unit_id = u.id
and p.town = ....

EDIT: So I just noticed the rest of your SQL. If you require to keep the many-to-many relationship table for the unit -> property relationship then you will need to join unit and property off of that table.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜