简体   繁体   中英

How can I select all rows in a table a, which have n characteristics given in a table b

I'm making a web page for renting houses.

the publications are stored in a table like this

ta_publications
+---+-------------+------+
|id |    name     | date |
+---+-------------+------+
| 1 | name_001    |  ... |
| 2 | name_002    |  ... |
| 3 | name_003    |  ... |
+---+-------------+------+

I have diferent publications, which have "features" such as "satellite tv", "Laundry cleaning", etc.

These features might change in the future, and I want to be able to add/remove/modify them, so I store them in the database in a table.

ta_feature_types
+---+-------------+
|id | name        |
+---+-------------+
| 1 | Internet    |
| 2 | Wi-Fi       |
| 3 | satelital tv|
+---+-------------+

which are related to the publications using a table

ta_features
+---+-------------+----------------+
|id |   type_id   | publication_id |
+---+-------------+----------------+
| 1 |      1      |       1        |
| 2 |      2      |       1        |
| 3 |      3      |       1        |
+---+-------------+----------------+

I think it's pretty easy to understand; There is a publication called name_001 which have internet, wi-fi and satellite tv.

My problem is: I need to be able to efficiently search and select all publications(houses) wich have certain features. For example, all publications that have internet, wifi and "pets-allowed" features.

I just came up with another question: When the user likes one publication, say "house_003", how do I get a list of the features that it does have?

If you want to get publications by feature name :

SELECT p.*
FROM ta_publications p
JOIN ta_features f ON f.publication_id = p.id
JOIN ta_feature_types t ON f.type_id = t.id
WHERE t.name = ? -- feature name

If you already know the feature ID :

SELECT p.*
FROM ta_publications p
JOIN ta_features f ON f.publication_id = p.id
WHERE f.type_id = ? -- feature ID

EDIT: To get all publications that match all of multiple feature IDs:

SELECT p.id, p.name
FROM pub p
JOIN pub_feat pf ON pf.pub_id = p.id
WHERE pf.feat_id IN ? -- list of feature IDs, e.g. (1,2,3)
GROUP BY p.id, p.name HAVING COUNT(*) = ? -- size of list of feature IDs, e.g. 3

To get all the features (names, I assume) by publication ID:

SELECT t.name
FROM ta_feature_types t
JOIN ta_features f ON f.type_id = t.id
JOIN ta_publications p ON f.publication_id = p.id
WHERE p.id = ? -- publication ID

Some notes on your schema:

  • As I commented above, you don't need an ID column in the ta_features table unless a publication can have the same features multiples times, eg "2x Wi-Fi"

  • Your table names are confusing, may I suggest you rename

    • ta_features to ta_publication_features (or ta_pub_features ) and
    • ta_feature_types to ta_features
  • For performance reasons you should create indices on all the columns used in the above JOIN conditions (using your original table names here):

    • ta_publications(id)
    • ta_features(type_id, publication_id)
    • ta_feature_types(id)

If the user selects multiple features use the IN keyword and a list of all features for a publication:

SELECT p.*
FROM ta_publications p
WHERE '1' in (select type_id from ta_features where publication_id = p.id)
AND '2' in (select type_id from ta_features where publication_id = p.id)
AND '3' in (select type_id from ta_features where publication_id = p.id)

You could generate the above with a loop in your server language of choice. ie.

SELECT p.*
FROM ta_publications p
WHERE 1=1
//START SERVER LANGUAGE
for (feature in featuresArray){
    print("AND '$feature' in (select type_id from ta_features where publication_id = p.id)");
}
//END SERVER LANGUAGE

I think what you want is a subquery:

select a.* 
from ta_publications as a
where '1' in (select type_id from ta_features where publication_id=a.id)

Substitute '1' for any other feature number you want.

For your second question. A simple query should do it:

select type_id 
from ta_features
where publication_id=[[[id that someone likes]]]

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