如何使用子查询的结果

时间:2018-03-21 14:13:01

标签: mysql sql subquery

我有三个SQL表,如下所示:

("订单"下表未完成)

enter image description here

如何使用一个SQL查询解决以下问题:

选择在2014年订购的所有产品(至少)客户命名为' Smith'在2013年订购。

这可能吗?

我考虑过这个问题:

  1. 首先,找到客户命名的所有产品" Smith"于2013年订购。

  2. 其次,找到至少在2014年订购了上述所有产品的客户名单。

  3. 这让我想到了这样的SQL查询:

    SELECT cname,
    FROM customers
    NATURAL JOIN orders
    WHERE YEAR(odate) = '2014'
      AND "do_something_here"
        (SELECT DISTINCT pid
         FROM orders
         NATURAL JOIN customers
         WHERE LOWER(cname)='smith'
           AND YEAR(odate)='2013') as results;
    

    其中应使用所有子查询结果(" Smith" 2013年订购的产品列表)来查找所需的客户。

    但我不知道这是不是一个好方法。

    对不起我的英语,因为我不是母语人士。

    如果你想在phpMyAdmin上测试一下,这里是SQL:

    -- phpMyAdmin SQL Dump
    -- version 4.7.5
    -- https://www.phpmyadmin.net/
    --
    -- Host: localhost
    -- Generation Time: Mar 21, 2018 at 02:49 PM
    -- Server version: 5.7.20
    -- PHP Version: 7.1.7
    
    SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
    SET AUTOCOMMIT = 0;
    START TRANSACTION;
    SET time_zone = "+00:00";
    
    
    /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
    /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
    /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
    /*!40101 SET NAMES utf8mb4 */;
    
    --
    -- Database: `tp1`
    --
    
    -- --------------------------------------------------------
    
    --
    -- Table structure for table `customers`
    --
    
    CREATE TABLE `customers` (
      `cid` int(11) NOT NULL,
      `cname` varchar(30) NOT NULL,
      `residence` varchar(50) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    --
    -- Dumping data for table `customers`
    --
    
    INSERT INTO `customers` (`cid`, `cname`, `residence`) VALUES
    (0, 'didnotorder', 'Great Britain'),
    (1, 'Jones', 'USA'),
    (2, 'Blake', NULL),
    (3, 'Dupond', 'France'),
    (4, 'Smith', 'Great Britain'),
    (5, 'Gupta', 'India'),
    (6, 'Smith', 'France');
    
    -- --------------------------------------------------------
    
    --
    -- Table structure for table `orders`
    --
    
    CREATE TABLE `orders` (
      `pid` int(11) NOT NULL,
      `cid` int(11) NOT NULL,
      `odate` date NOT NULL,
      `quantity` int(11) NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    --
    -- Dumping data for table `orders`
    --
    
    INSERT INTO `orders` (`pid`, `cid`, `odate`, `quantity`) VALUES
    (1, 1, '2014-12-12', 2),
    (1, 4, '2014-11-12', 6),
    (2, 1, '2014-06-02', 6),
    (2, 1, '2014-08-20', 6),
    (2, 1, '2014-12-12', 2),
    (2, 2, '2010-11-12', 1),
    (2, 2, '2014-07-21', 3),
    (2, 3, '2014-10-01', 1),
    (2, 3, '2014-11-12', 1),
    (2, 4, '2014-01-07', 1),
    (2, 4, '2014-02-22', 1),
    (2, 4, '2014-03-19', 1),
    (2, 4, '2014-04-07', 1),
    (2, 4, '2014-05-22', 1),
    (2, 4, '2014-09-12', 4),
    (2, 6, '2014-10-01', 1),
    (3, 1, '2014-12-12', 1),
    (3, 2, '2013-01-01', 1),
    (3, 4, '2015-10-12', 1),
    (3, 4, '2015-11-12', 1),
    (4, 1, '2014-12-12', 3),
    (4, 2, '2014-06-11', 2),
    (4, 5, '2014-10-12', 1),
    (4, 5, '2014-11-13', 5),
    (5, 2, '2015-07-21', 3),
    (6, 2, '2015-07-21', 7),
    (6, 3, '2014-12-25', 1);
    
    -- --------------------------------------------------------
    
    --
    -- Table structure for table `products`
    --
    
    CREATE TABLE `products` (
      `pid` int(11) NOT NULL,
      `pname` varchar(30) NOT NULL,
      `price` decimal(7,2) NOT NULL,
      `origin` varchar(20) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    --
    -- Dumping data for table `products`
    --
    
    INSERT INTO `products` (`pid`, `pname`, `price`, `origin`) VALUES
    (0, 'wasnotordered', '11.00', NULL),
    (1, 'chocolate', '5.00', 'Belgium'),
    (2, 'sugar', '0.75', 'India'),
    (3, 'milk', '0.60', 'France'),
    (4, 'tea', '10.00', 'India'),
    (5, 'chocolate', '7.50', 'Switzerland'),
    (6, 'milk', '1.50', 'France');
    
    --
    -- Indexes for dumped tables
    --
    
    --
    -- Indexes for table `customers`
    --
    ALTER TABLE `customers`
      ADD PRIMARY KEY (`cid`);
    
    --
    -- Indexes for table `orders`
    --
    ALTER TABLE `orders`
      ADD PRIMARY KEY (`pid`,`cid`,`odate`),
      ADD KEY `orders_fk_cid` (`cid`);
    
    --
    -- Indexes for table `products`
    --
    ALTER TABLE `products`
      ADD PRIMARY KEY (`pid`);
    
    --
    -- Constraints for dumped tables
    --
    
    --
    -- Constraints for table `orders`
    --
    ALTER TABLE `orders`
      ADD CONSTRAINT `orders_fk_cid` FOREIGN KEY (`cid`) REFERENCES `customers` (`cid`),
      ADD CONSTRAINT `orders_fk_pid` FOREIGN KEY (`pid`) REFERENCES `products` (`pid`);
    COMMIT;
    
    /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
    /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
    /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
    

2 个答案:

答案 0 :(得分:0)

您可以尝试以下内容。基本上强制加入客户与2013年史密斯的所有产品,然后LEFT JOIN与每个客户2014年购买的产品。如果两个数量相等意味着2013年史密斯的所有产品在2014年至少购买一次,为每个客户。

SELECT
    C.cid
FROM
    Customers C

    CROSS JOIN (
        SELECT DISTINCT
            P.pid
        FROM
            Customers C
            INNER JOIN Orders O ON C.cid = O.cid
            INNER JOIN Products P ON O.pid = P.pid
        WHERE
            C.cname = 'Smith' AND
            YEAR(O.odate) = 2013) X

    LEFT JOIN (
        SELECT DISTINCT
            C.cid,
            P.pid
        FROM
            Customers C
            INNER JOIN Orders O ON C.cid = O.cid
            INNER JOIN Products P ON O.pid = P.pid
        WHERE
            YEAR(O.odate) = 2014) R ON C.cid = R.cid AND X.pid = R.pid
GROUP BY
    C.cid
HAVING
    COUNT(X.pid) = COUNT(R.pid)

如果您想查看客户,即使2013年没有史密斯产品,您也可以切换CROSS JOIN FULL JOIN (...) X ON 1 = 1

答案 1 :(得分:0)

您可以通过查找每个cid与史密斯客户共有的所有产品来解决此问题。然后,只需检查计数是否涵盖所有产品:

select o2014.cid, count(distinct o2013.pid) as num_products,
       group_concat(distinct o2013.pid) as products
from orders o2013 join
     orders o2014
     on o2013.pid = o2014.pid and
        year(o2013.odate) = 2013 and year(o2014.odate) = 2014
where o2013.cid = (select c.cid from customers c where c.cname = 'Smith')
group by o2014.cid
having num_products = (select count(distinct o2013.products)
                       from orders o2013
                       where o2013.cid = (select c.cid from customers c where c.cname = 'Smith')
                      );