编程渣王爽 2019-04-07
SQL是一种用于与数据库通信的编程语言,是技术行业招聘中需要掌握的最有用的技能之一。SQL是结构化查询语言的缩写,这个惊人的工具是分析大型数据集的必备工具。当它应用于关系数据库(以某种方式相互关联的唯一数据表)时,它的优点尤其明显。
由于SQL在技术领域无处不在,许多公司在给出工作邀请之前都会进行SQL面试。这有助于确保求职者(尤其是从事项目管理、分析、商业智能和软件工程相关工作的人员)能够轻松地在工作中使用SQL。
如果你即将进行SQL面谈,你或许想知道可能会遇到什么样的问题。招聘人员通常对细节含糊其辞,像这样一无所知地开始一场谈话会让人不知所措。
因此,我们列出了7个最常见的SQL面试问题,以便你在面试前进行一些练习。通过一些预先准备,你会在面试日感觉到胸有成竹、自信满满。
虽然你可能知道关系数据库是什么以及SQL是什么,但很难在面试现场给出连贯、简洁的解释。为此,请确保你已提前准备好回答这个简单的问题。以下是一些答题小技巧:
关系数据库是一组数据表,以某种方式相互链接或关联。它用于存储不同类型的信息,这些信息可以汇集起来回答特定的分析问题。这是在不丢失任何关键信息的情况下,最大限度地减少存储在服务器上的数据量一种有效方法。
这是一个模糊的定义,所以让我们看看实际中的关系数据库。在线零售商的关系数据库的简单版本可能包含两个单独的数据表:
当然,如果我们只在Orders 表中包含客户信息,就不需要多表数据库。但这并不是特别有效:如果一个客户下了多个订单,他或她的姓名、联系信息和发货偏好将列在Orders 表的多行上,从而导致不必要的重复和无法管理的大型数据库。相反,我们创建了一个关系数据库来节省空间,并展示了不同数据块是如何链接在一起的。
那么,SQL只是用于与这个关系数据库通信的语言。数据库还不能理解像英语这样的人类语言——英语在语法上太复杂了——所以我们使用一种它们能够理解的标准化的语言来与它们交流。
在SQL中,JOIN子句用于返回将两个或多个其他表的内容合并在一起的表。 例如,如果我们有两个表——一个包含Customers信息,另一个包含各个客户订购的Orders 信息——我们可以使用JOIN子句将它们组合在一起并创建一个新表:客户的完整订单列表,提供所有必要的信息以便发货。
有多种类型的JOIN子句,它们的功能稍微有所不同:
orders表中总共有1000行:
SELECT * FROM orders; -- 1000 rows in set (0.05 sec)
其中23个订单来自customer_id = 45的用户:
SELECT * FROM orders WHERE customer_id = 45; -- 23 rows in set (0.10 sec)
然而,当我们选择不是来自customer_id = 45的订单数量时,我们只得到973个结果:
SELECT * FROM orders WHERE customer_id <> 45; -- 973 rows in set (0.11 sec)
973 + 23 = 996。但是,customer_id =45加上customer_id不等于45的订单数量不应该等于1000吗?为什么此查询未返回预期结果?
答案是:此数据集很可能包含具有 customer_id为空的order值。在条件中使用SELECT子句时,具有空值的行与=或<>运算符不匹配。
上面我们所指的第二个查询可以修改如下,以产生预期的结果:
SELECT * FROM orders WHERE (customer_id <> 45 OR customer_id IS NULL); -- 977 rows in set (0.11 sec)
请看以下查询,该查询返回预期结果:
SELECT CASE WHEN (3 IN (1, 2, 3, NULL)) THEN 'Three is here!' ELSE "Three isn't here!" END AS result; /* +----------------+ | result | +----------------+ | Three is here! | +----------------+ 1 row in set (0.00 sec) */ 输出中显示"Three is here!",因为值3包含在IN子句中。但是以下查询呢? SELECT CASE WHEN (3 NOT IN (1, 2, NULL)) THEN "Three isn't here!" ELSE 'Three is here!' END AS result; /* +----------------+ | result | +----------------+ | Three is here! | +----------------+ 1 row in set (0.00 sec) */
第二个数据集中不包含3,所以为什么我们的查询错误地输出了"Three is here!"?
答案再一次与MYSQL处理NULL值的方式有关。让我们仔细看看。在我们的第一个查询中,我们询问值3是否包含在集合中(1, 2, 3, NULL)。我们的语句在功能上等同于以下内容:
SELECT CASE WHEN ((3 = 1) OR (3 = 2) OR (3 = 3) OR (3 = NULL)) THEN 'Three is here!' ELSE "Three isn't here!" END AS result; /* +----------------+ | result | +----------------+ | Three is here! | +----------------+ 1 row in set (0.00 sec) */
由于3绝对等于3,所以满足了我们的OR条件之一,语句输出"Three is here!"。另一方面,我们的第二个语句询问值3是否未包含在集合中(1, 2, NULL)。此语句在功能上等同于以下内容:
SELECT CASE WHEN ((3 <> 1) AND (3 <> 2) AND (3 <> NULL)) THEN "Three isn't here!" ELSE "Three is here!" END AS result; /* +----------------+ | result | +----------------+ | Three is here! | +----------------+ 1 row in set (0.00 sec) */
在这种情况下,条件检查3 <> NULL失败,因为在ANSI标准SQL中,我们需要使用IS NULL语句而不是<>运算符。
customers和 orders表具有以下相应的结构:
CREATE TABLE `customers` ( `customer_id` int(11) NOT NULL AUTO_INCREMENT, `first_name` varchar(255) NOT NULL, `last_name` varchar(255) NOT NULL, `email` varchar(255) NOT NULL, `address` varchar(255) DEFAULT NULL, `city` varchar(255) DEFAULT NULL, `state` varchar(2) DEFAULT NULL, `zip_code` varchar(5) DEFAULT NULL, PRIMARY KEY (`customer_id`) ); CREATE TABLE `orders` ( `order_id` int(11) NOT NULL AUTO_INCREMENT, `customer_id` int(11) NOT NULL, `order_placed_date` date NOT NULL, PRIMARY KEY (`order_id`), KEY `customer_id` (`customer_id`), FOREIGN KEY (`customer_id`) REFERENCES `customers` (`customer_id`) );
你是否可以构造一个简单的SELECT 语句,该语句使用INNER JOIN来组合来自customers和orders表的所有信息?
这里的答案非常简单。我们是这样做到的:
SELECT * FROM orders INNER JOIN customers on orders.customer_id = customers.customer_id;
我们根据上面的orders表编写了一个查询,以选择2016年的所有订单。但是我们的查询有错。你能找出问题出在哪儿吗?
SELECT order_id, customer_id, YEAR(order_placed_date) AS order_year FROM orders WHERE order_year = 2016;
答案是:order_year是一个别名,意味着它被用作更复杂引用的另一个名称:YEAR(order_placed_date)。 事实证明,在SQL中,别名只能在 GROUP BY、 ORDER BY 和 HAVING子句中引用 - 它们不能在WHERE子句中使用。 运行上面的代码将产生以下结果:
--ERROR 1054 (42S22): Unknown column 'order_year' in 'where clause'
要解决这个问题,我们需要重申WHERE子句中order_year别名的定义,如下所示:
SELECT order_id, customer_id, YEAR(order_placed_date) AS order_year FROM orders WHERE YEAR(order_placed_date) = 2016; --498 rows in set (0.00 sec)
请看以下数据库结构:
CREATE TABLE `products` ( `product_id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `price` decimal(19,4) NOT NULL, PRIMARY KEY (`product_id`) ); CREATE TABLE `order_products` ( `order_product_id` int(11) NOT NULL AUTO_INCREMENT, `order_id` int(11) NOT NULL, `product_id` int(11) NOT NULL, PRIMARY KEY (`order_product_id`), KEY `order_id` (`order_id`), KEY `product_id` (`product_id`), FOREIGN KEY (`order_id`) REFERENCES `orders` (`order_id`), FOREIGN KEY (`product_id`) REFERENCES `products` (`product_id`) )
你是否可以编写一个可以查找所有order_ids 的 product.price 的查询?(例如,每个订单的product.price的总和)
这个问题有点棘手,因为我们必须同时使用SUM函数和 GROUP BY子句并通过order_id聚合订单。我们是这样做的:
SELECT order_id, SUM(price) AS total_order_price FROM order_products INNER JOIN products ON order_products.product_id = products.product_id GROUP BY order_id; --1000 rows in set (0.01 sec)