大手 LeetCode メーカーにおける SQL 面接の質問に対する解決策 (1)

皆さんこんにちは、私の名前はニンイーです。

最近はグループ内でSQLの話題を毎日更新していきます。

それは間接的に私にもっと頑張ろうという気持ちにもなりました——

トピック 1:

182. 重複するメールアドレスを見つける(簡単)

SQL クエリを作成して、Person テーブル内の重複する電子メール アドレスをすべて検索します。

例:

+----+---------+
| Id | Emai    |
+----+---------+
|1 |  [email protected] |
| 2 | [email protected]  |
|3 | [email protected]  |
+----+---------+

上記の入力に基づいて、クエリは次の結果を返すはずです。

+---------+
| Email   |
+---------+
| [email protected] |
+---------+

問題解決のアイデア:

最初にサブクエリを使用し、count 集計関数を group by と組み合わせて使用​​して、各メールボックスの数をクエリできます。次に、親クエリを使用して、メールボックス番号が 1 より大きいレコードを特定します。これが、取得したい最終結果です。

ステップ 1:
サブクエリを使用して、各メールボックスの番号を確認します。

SELECT Email FROM(
  SELECT Email, COUNT(Email) AS num
  FROM Person
  GROUP BY Email

ステップ 2:
最初のステップで取得した結果に基づいて、メールボックス番号 num が 1 より大きいレコードを特定します。

SELECT Email FROM(
  SELECT Email, COUNT(Email) AS num
  FROM Person
  GROUP BY Email
) AS a
WHERE num > 1;

自分のコンピュータでローカルにテストしたい場合は、これを使用してデータベース ステートメントをすばやく作成できます。

-- 创建数据库
CREATE database SQLCode;
-- 选择数据库
USE SQLCode;


-- 创建科目表Person 
CREATE TABLE Person(
Id INT,
Email VARCHAR(10));
-- 插入语句
INSERT INTO Person VALUES
(1,'[email protected]'),
(2,'[email protected]'),
(3,'[email protected]');

トピック 2:

176. 2番目に給料が高い(楽)

Employee テーブルで 2 番目に高い給与を取得して返す SQL クエリを作成します。2 番目に高い給与が存在しない場合、クエリは null を返す必要があります。

例 1:

入力: 従業員テーブル

+----+--------+
| id | salary |
+----+--------+
|  1 | 100    |
|  2 | 200    |
|  3 | 300    |
+----+--------+

出力:

+---------------------+
| SecondHighestSalary |
+---------------------+
| 200                 |
+---------------------+

例 2:

入力: 従業員テーブル:

+----+--------+
| id | salary |
+----+--------+
| 1  | 100    |
+----+--------+

出力:

+---------------------+
| SecondHighestSalary |
+---------------------+
| null                |
+---------------------+

問題解決のアイデア:

さまざまな給与を降順に並べ替え、LIMIT OFFSET を使用して 2 番目に高い給与を取得します。

ただし、テーブル内に給与の異なるデータが2つ未満の場合は空になるので、IFNULLを追加して判定します。

知識ポイント:

(1) LIMIT 句の基本的な使い方:

返されるレコードの数を制限するために使用されます。

LIMIT m,n によって結果セットの最初の m レコードをスキップし、n 個のレコードを取得できます。この文は少しわかりにくいので、例を挙げてみましょう。

7 番目から 9 番目のレコードを取得します。つまり、最初の 6 レコードをスキップして、7 番目のレコードから開始して、7、8、9 の 3 つのレコードを取得します。これは、LIMIT 6,3 を使用して達成する必要があります。

(2) IFNULL ステートメントの基本構文:

IFNULL(値1,値2)

値 1 が NULL の場合は値 2 を返し、値 1 が NULL でない場合は値 1 を返します。

最初の一歩:

給与を逆順に並べ替え、DISTINCT を使用して重複を削除し、LIMIT 1,1 を使用して 2 番目に高い給与を取得します。

SELECT DISTINCT Salary
FROM Employee
ORDER by Salary DESC
LIMIT 1,1 # 获取第二高的salary

ステップ2:

2 番目に高い給与がない場合は、null を返し、IFNULL を使用して達成します。

SELECT IFNULL(
    (
        SELECT DISTINCT Salary
        FROM Employee
        ORDER by Salary DESC
        LIMIT 1,1 # 获取第二高的salary
    ),
    NULL # 如果没有,则为 NULL
)

自分のコンピュータでローカルにテストしたい場合は、これを使用してデータ テーブル ステートメントをすばやく作成できます。

-- 创建员工表Employee 
CREATE TABLE Employee(
Id INT,
salary INT);
-- 插入语句
INSERT INTO Employee VALUES
(1,100),
(2,200),
(3,300);

トピック 3:

180. 連続数字(中)

表: ログ

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
|  id         | int     |
| num         | varchar |
+-------------+---------+

id はこのテーブルの主キーです。

SQL クエリを作成して、少なくとも 3 回連続して出現するすべての数値を検索します。

返される結果テーブルのデータは任意の順序で指定できます。

例 1:

入力: ログテーブル

+----+-----+
| Id | Num |
+----+-----+
| 1  | 1   |
| 2  | 1   |
| 3  | 1   |
| 4  | 3   |
| 5  | 2   |
| 6  | 2   |
| 7  | 2   |
+----+-----+

出力:

+-----------------+
| ConsecutiveNums |
+-----------------+
| 1               |
| 2               |
+-----------------+

問題解決のアイデア:

id+1で次回に出現する数字を求め、id+2で次回に出現する数字を求めます。主に、次回と次回に出現する数字は現在の数字と同じです。少なくとも3回出現するのが条件です。

ナレッジポイント: JOIN 接続

複数のデータ テーブルの結合クエリを実行するには、JOIN 接続の使用が必要です。JOIN 接続にはいくつかの種類があります。この質問では、内部結合を使用しました。

INNER JOIN: 内部接続。単に JOIN と書くこともできます。接続基準に一致するデータのみが、結合される 2 つのテーブルに保持されます。これは、2 つのテーブルの交差部分に相当します。前後で同じテーブルを結合する場合、自己結合とも呼ばれます。

最初の一歩:

次回に出現する番号と次回に出現する番号を同じ表に入れて、2 番目のステップで比較しやすくします。

SELECT *
FROM Logs t1
JOIN Logs t2
ON t1.id+1=t2.id
JOIN Logs t3
ON t1.id+2=t3.id

ステップ2:

フィルタ条件を追加すると、テーブル t1 の数値とテーブル t2 の数値、およびテーブル t3 の数値は等しくなります。

SELECT *
FROM Logs t1
JOIN Logs t2
ON t1.id+1=t2.id
JOIN Logs t3
ON t1.id+2=t3.id
WHERE t1.Num=t2. Num
    AND t1.Num=t3.Num;

3番目のステップ:

SELECT の後のフィールドを変更し、NUM のみを出力します。

SELECT DISTINCT t1.Num
FROM Logs t1
JOIN Logs t2
ON t1.id+1=t2.id
JOIN Logs t3
ON t1.id+2=t3.id
WHERE t1.Num=t2. Num
    AND t1.Num=t3.Num;

自分のコンピュータでローカルにテストしたい場合は、これを使用してデータ テーブル ステートメントをすばやく作成できます。

-- 创建表
CREATE TABLE Logs(
Id INT,
Num INT);
-- 插入语句
INSERT INTO Logs VALUES
(1,1),
(2,1),
(3,1),
(4,3),
(5,2),
(6,2),
(7,2);

トピック 4:

1454. アクティブ ユーザー (中)

これで、Accounts テーブルができました。このテーブルには、アカウント ID とアカウントのユーザー名が含まれています。

ログイン テーブル: ログイン ユーザーのアカウント ID とログイン日、login_date が含まれます。(ユーザーは1日に複数回ログインすることができます)

SQL クエリを作成して、アクティブ ユーザーの ID と名前を検索します。アクティブ ユーザーとは、少なくとも連続 3 日間アカウントにログインしているユーザーです。返された結果テーブルは ID によって並べ替えられます。

結果テーブルの形式は次の例に示すとおりです。

アカウントテーブル:

+----+----------+
| id | name     |
+----+----------+
| 1  | '小王'    |
| 7  | ‘小李'    |
+----+----------+

ログインテーブル:

+----+------------+
| id | login_date |
+----+------------+
| 7  | 2020-05-30 |
| 1  | 2020-05-30 |
| 7  | 2020-05-31 |
| 7  | 2020-06-01 |
| 7  | 2020-06-03 |
| 1  | 2020-06-07 |
+----+------------+

ID = 1 のユーザー Xiao Wang は 2 回しかログインしていないため、Xiao Wang はアクティブなユーザーではありません。

ID = 7 のユーザー、Xiao Li は 3 日間連続してログインしているため、Xiao Li はアクティブ ユーザーです。

問題解決のアイデア:

これも連続問題で、上記の連続数を求める考え方と同じで、まず自己結合を使ってAccountsテーブルとLoginsテーブルを接続します。

Logins テーブルを再度接続し、エイリアスに L2 という名前を付け、同じ ID を持ち、2 日以内の差がある L1 テーブル内の日付のみを接続します。このようにして、L1 テーブルと 2 日異なる日付がすべて表示されます。

たとえば、L1 テーブルでは 5 月 30 日があり、L2 テーブルでは最大で 5 月 30 日、5 月 31 日、および 6 月 1 日の日付が見つかります。3 つの日付に対応する場合、ユーザーが 3 日間連続してログインしたことを意味します。日付が 2 つある場合は、ユーザーが 3 日間のうち 2 日間しかログインしていないことを意味します。

知識ポイント:

DATEDIFF は、2 つの日付の間の日数を計算します。

SELECT
  DATEDIFF('2022-04-11','2021-04-11') AS "间隔天数",
  DATEDIFF('2022-04-11 01:00','2022-04-10 23:00') AS "间隔天数"

最初の一歩:

まずテーブルを接続し、同じ ID を持ち、互いに 2 日以内にある L1 テーブルと L2 テーブルの日付を見つけます。

SELECT A.*,L1.login_date,L2.login_date
FROM Accounts A
JOIN logins L1 ON A.id = L1.id
JOIN Logins L2 ON L1.id=L2.id
    AND DATEDIFF(L2.login_date,L1.login_date) BETWEEN 0 AND 2

ステップ2:

上記で見つかった結果をグループ化し、L2 テーブル内の日付の数に対応する、L1 テーブル内の同じ日付を調べます。

SELECT A.*,L1.login_date
FROM Accounts A
JOIN logins L1 ON A.id = L1.id
JOIN Logins L2 ON L1.id=L2.id
    AND DATEDIFF(L2.login_date,L1.login_date) BETWEEN 0 AND 2
GROUP BY A.id,A.name,L1.login_date

3番目のステップ:

上の表の 3 つのレコードに対応する口座番号が探しているものです。次に、SELECT の後のフィールドを削除し、Account フィールドだけを残します。

SELECT A.*
FROM Accounts A
JOIN logins L1 ON A.id = L1.id
JOIN Logins L2 ON L1.id=L2.id
    AND DATEDIFF(L2.login_date,L1.login_date) BETWEEN 0 AND 2
GROUP BY A.id,A.name,L1.login_date
HAVING COUNT(DISTINCT L2.login_date)=3

自分のコンピュータでローカルにテストしたい場合は、これを使用してデータ テーブル ステートメントをすばやく作成できます。

-- 创建表
CREATE TABLE Accounts(
Id INT,
name VARCHAR(10));
-- 插入语句
INSERT INTO Accounts VALUES
(1,'小王' ),
(7, '小李');
-- 创建表
CREATE TABLE Logins(
Id INT,
login_date DATETIME);
-- 插入语句
INSERT INTO Logins VALUES
(7,'2020-05-30' ),
(1,'2020-05-30' ),
(7,'2020-05-31' ),
(7,'2020-06-01' ),
(7,'2020-06-03' ),
(1,'2020-06-07' );

クリックしてフォローして、迷うことなくプログラミングを始めましょう~

おすすめ

転載: blog.csdn.net/shine_a/article/details/127201711