皆さんこんにちは、私の名前はニンイーです。
最近はグループ内で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' );
クリックしてフォローして、迷うことなくプログラミングを始めましょう~