Domanda

I'm having trouble wrapping my head around a query with a subquery. Follow along, if you will:

SAMPLE DATA:

CREATE TABLE users (
    user_id INT(10) NOT NULL AUTO_INCREMENT,
    username VARCHAR(64),
    PRIMARY KEY (user_id)
);

CREATE TABLE cars {
    car_id INT(10) NOT NULL AUTO_INCREMENT,
    user_id INT(10),
    caryear YEAR(4),
    carmaker VARCHAR(32),
    carmodel VARCHAR(32),
    PRIMARY KEY (car_id, user_id)
    FOREIGN KEY(`user_id`) references users(`user_id`)
) ENGINE=InnoDB;    

INSERT INTO users (user_id, name) VALUES (1,'Bob'),(2,'John'),(3,'Sally');
INSERT INTO cars (user_id, caryear, carmaker, carmodel) VALUES
(1,'2004','Audi','A4'),
(1,'2006','Toyota','Camry'),
(1,'2014','Jeep','CJ'),
(2,'1998','Acura','CL'),
(2,'2014','Honda','Accord'),
(3,'2011','Jeep','Rubicon')

Okay, so if I want to get a list of users and their cars, I can do something like this:

SELECT
  user_id,
  username,
  (SELECT GROUP_CONCAT(CONCAT(CarYear,' ',CarMaker,' ',CarModel))
   FROM cars
   WHERE cars.user_id = users.user_id
  ) AS Cars
FROM users;

But how can I get a list of users that own a 2004-2014 Jeep, for instance?

I've come up with this, but I'm sure there is a more elegant approach:

SELECT
  user_id,
  username,
  (SELECT GROUP_CONCAT(CONCAT(CarYear,' ',CarMaker,' ',CarModel))
   FROM cars
   WHERE cars.user_id = users.user_id
   AND CarMaker = 'Jeep'
   AND CarYear BETWEEN 2004 AND 2014
  ) AS Cars
FROM users
HAVING Cars is not null;

The problem with this solution is that it does not show the other cars owned by people who own 2004-2014 Jeeps.

Any advice?

È stato utile?

Soluzione

To show the users and a list of all their cars, for any user who owns a Jeep 2004-2014:

SELECT
  u.user_id,
  u.username,
  GROUP_CONCAT(CONCAT(c.CarYear,' ',c.CarMaker,' ',c.CarModel)) AS Cars
FROM users u
INNER JOIN cars c USING (user_id)
INNER JOIN (
  SELECT DISTINCT user_id FROM cars
  WHERE c.CarMaker = 'Jeep' 
    AND c.CarYear BETWEEN 2004 AND 2014) AS j USING (user_id)
GROUP BY u.user_id, u.username;

Altri suggerimenti

Because this is a many-to-many relationship, you actually need to break cars into two tables. The first table will be the same as cars is now, except remove user_id from it. The second table (call it user_car) has two columns: user_id and car_id.

Once you do that, the query is simple:

SELECT user_id FROM user_car WHERE car_id IN
    (SELECT car_id FROM cars
   WHERE CarMaker = 'Jeep'
   AND CarYear BETWEEN 2004 AND 2014
  )

If you need to pull data straight from users, expand the query to:

SELECT user_id, username FROM users WHERE user_id IN
  (SELECT user_id FROM user_car WHERE car_id IN
    (SELECT car_id FROM cars
   WHERE CarMaker = 'Jeep'
   AND CarYear BETWEEN 2004 AND 2014
  ))

INNER JOIN would do the trick.

SELECT u.* FROM users u
INNER JOIN cars c ON c.user_id = u.user_id
WHERE CarMaker = 'Jeep' AND CarYear BETWEEN 2004 AND 2014 

inner join

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top