20201121のMySQLに関する記事は8件です。

SQL初心者〜中級者のための練習問題&解答例1

SQL初心者〜中級者のための練習問題+解答例をいくつか作ってみました。
SQL力向上のためにお役立てください。

その2: SQL初心者〜中級者のための練習問題&解答例2
その3: SQL初心者〜中級者のための練習問題&解答例3

ツールの紹介

DB Fiddleを使うとブラウザ上で簡単にSQLを実行できます。
画面左側のSchema SQLにスキーマを、画面右側のQuery SQLにクエリ(SELECT句)を書いて、画面上部の「Run」ボタンを押すだけです。
環境構築要らないので便利です。

題材

学生テーブル

学籍番号 氏名 性別
0001 長岡 一馬
0002 中本 知佳
0003 松本 義文
0004 佐竹 友香

試験結果テーブル

学籍番号 教科 点数
0001 国語 30
0001 英語 30
0002 国語 70
0002 数学 80
0003 理科 92
0004 社会 90
0004 理科 35
0004 英語 22

Schema SQL
CREATE TABLE `students` (
  `id` int(4) unsigned zerofill NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `name` varchar(255) NOT NULL,
  `gender` varchar(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `students` (`id`, `name`, `gender`)
VALUES
    (0001, '長岡 一馬', '男'),
    (0002, '中本 知佳', '女'),
    (0003, '松本 義文', '男'),
    (0004, '佐竹 友香', '女');

CREATE TABLE `exam_results` (
  `student_id` int(4) unsigned zerofill NOT NULL,
  `subject` varchar(255) NOT NULL,
  `score` bigint(20) unsigned NOT NULL,
  PRIMARY KEY(`student_id`, `subject`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `exam_results` (`student_id`, `subject`, `score`)
VALUES
    (0001, '国語', 30),
    (0001, '英語', 30),
    (0002, '国語', 70),
    (0002, '数学', 80),
    (0003, '理科', 92),
    (0004, '社会', 90),
    (0004, '理科', 35),
    (0004, '英語', 22);

問1

性別が男である生徒の名前を一覧で表示せよ。

name
長岡 一馬
松本 義文

解答例
SELECT
    name
FROM
    students
WHERE
    gender = '男'

問2

1教科でも30点以下の点数を取った生徒の名前を一覧で表示せよ。
ただし、重複は許さないものとする。

name
長岡 一馬
佐竹 友香

解答例
SELECT DISTINCT
    s.name
FROM
    exam_results er
INNER JOIN students s
    ON er.student_id = s.id
WHERE
    er.score <= 30

問3

性別ごとに、最も高かった試験の点数を表示せよ。

gender max_score
92
90

解答例
SELECT
    s.gender,
    MAX(er.score) AS max_score
FROM
    students s
INNER JOIN exam_results er
    ON s.id = er.student_id
GROUP BY
    s.gender

問4

教科ごとの試験の平均点が50点以下である教科を表示せよ。

subject avg_score
国語 50.0000
英語 26.0000

解答例
SELECT
    subject,
    AVG(score) AS avg_score
FROM
    exam_results
GROUP BY
    subject
HAVING
    AVG(score) <= 50

問5

試験結果テーブルの点数の右に、その教科の平均点を表示せよ。

student_id subject score subject_avg_score
0001 国語 30 50.0000
0001 英語 30 26.0000
0002 国語 70 50.0000
0002 数学 80 80.0000
0003 理科 92 63.5000
0004 理科 35 63.5000
0004 社会 90 90.0000
0004 英語 22 26.0000

解答例
SELECT
    er1.*,
    (
        SELECT
            AVG(er2.score)
        FROM
            exam_results er2
        WHERE
            er1.subject = er2.subject
    ) AS subject_avg_score
FROM
    exam_results er1

問6

試験結果に理科が含まれない生徒の名前を一覧で表示せよ。

name
長岡 一馬
中本 知佳

解答例
SELECT
    s.name
FROM
    students s
INNER JOIN exam_results er
    ON s.id = er.student_id
GROUP BY
    s.id
HAVING
    SUM(CASE WHEN er.subject = '理科'  THEN 1 ELSE 0 END) = 0

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

前年度と比較を行う

年と売り上げを持つテーブルがある。

select * from sales;

+------+------+
| year | sale |
+------+------+
| 1990 |   50 |
| 1991 |   51 |
| 1992 |   52 |
| 1993 |   52 |
| 1994 |   50 |
| 1995 |   50 |
| 1996 |   49 |
| 1997 |   55 |
+------+------+

前年度の売り上げと比較し、結果に応じた出力を行う。

select
s1.year
,s1.sale
,case 
when sale = 
(
    select
    sale
    from
    sales s2
    where
    s2.year = s1.year -1
) then '→'
when sale >
(
    select
    sale
    from
    sales s2
    where
    s2.year = s1.year -1
) then '↑'
when sale <
(
    select
    sale
    from
    sales s2
    where
    s2.year = s1.year -1
) then '↓'
else '-' end as var
from
sales s1
order by year;

+------+------+-----+
| year | sale | var |
+------+------+-----+
| 1990 |   50 | -   |
| 1991 |   51 |    |
| 1992 |   52 |    |
| 1993 |   52 |    |
| 1994 |   50 |    |
| 1995 |   50 |    |
| 1996 |   49 |    |
| 1997 |   55 |    |
+------+------+-----+

相関サブクエリの結合条件で-1とすることで
前年度のレコードを比較対象としている。

次は時系列に歯抜けがある場合

select * from sales2;

+------+------+
| year | sale |
+------+------+
| 1990 |   50 |
| 1992 |   50 |
| 1993 |   52 |
| 1994 |   55 |
| 1997 |   55 |
+------+------+
select
s1.year
,s1.sale
,case
    when sale = (
        select
        sale
        from
        sales2 s2
        where
        year = (
            select
            max(year)
            from
            sales s3
            where
            s1.year > s3.year
        )
    ) then '→'
    when sale > (
        select
        sale
        from
        sales2 s2
        where
        year = (
            select
            max(year)
            from
            sales s3
            where
            s1.year > s3.year
        )
    ) then '↑'
    when sale < (
        select
        sale
        from
        sales2 s2
        where
        year = (
            select
            max(year)
            from
            sales s3
            where
            s1.year > s3.year
        )
    ) then '↓'
    else '-' end as var
from
sales2 s1

+------+------+-----+
| year | sale | var |
+------+------+-----+
| 1990 |   50 | -   |
| 1992 |   50 | -   |
| 1993 |   52 |    |
| 1994 |   55 |    |
| 1997 |   55 | -   |
+------+------+-----+

上記2つのSQLでは3回サブクエリを実行しているが、
1つにまとめられるようだ。

SELECT 
S1.year
,S1.sale
,CASE SIGN(sale - (
    SELECT sale
    FROM Sales S2
    WHERE S2.year = S1.year - 1)
)
WHEN 0  THEN '→'  /* 横ばい */
WHEN 1  THEN '↑'  /* 成長   */
WHEN -1 THEN '↓'  /* 後退   */
ELSE '-' END AS var
FROM Sales S1
ORDER BY year;

こちらを参考にさせていただきました。
達人に学ぶSQL徹底指南書 第2版 初級者で終わりたくないあなたへ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQLと MariaDBの比較

RDBのMySQLとMariaDB

どちらも開発者は同じでMyは長女、Mariaは次女の名前だそう。

MySQL

  • MySQL自体の歴史が長く、現在はIT大手のOracle社が開発を担当しているので安心感がある。
  • CMS(コンテンツ・マネジメント・システム)に積極的に採用されている。Wordpressなど。
  • 「Youtube」や「Netflix」が使用している。

MariaDB

  • MySQLの派生でビッグデータの集計を得意としている。
  • 冗長構成(情報システムなどの構成の一種で、設備や装置を複数用意し、一部が故障しても運用を継続できるようにしたもの。)を構築できる仕組みが提供されている。
  • クラスタ構成(複数のサーバを連携させて利用者や他のサーバから、全体で1台のサーバであるかのように動作させる技術)データベース構築を行える。
  • 負荷分散の仕組みが提供されている。
  • 「SAMSUNG」や「NOKIA」が使用している。

まとめ

MariaDBの方がMySQLよりも高スペックな上に多機能である。
大きなデータを扱う時にはMariaDBの方が高速に処理できる。

参考

https://www.winserver.ne.jp/column/about_mariadb/
https://style.potepan.com/articles/19653.html#MySQLMariaDB-2

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ユニーク制約のキーの長さに制限がある場合の重複チェックについての確認(MySQL)

やりたいこと

MySQL 8.0で2つの文字列を格納する列(VARCHAR(2000))を持つテーブルを作成して、その2つの列の組み合わせにユニーク制約を設定したい。
例えばSQLで書くと以下のとおり。

CREATE TABLE testtable (
    id INT PRIMARY KEY,
    text1 VARCHAR(2000),
    text2 VARCHAR(2000),
    UNIQUE (text1, text2)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ただし、これを実行すると以下のようなエラーとなってしまう。

ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes

このエラーが出る理由であるが、ユニーク制約を設定すると自動的にインデックスが作成され、以下の制限(公式のドキュメント)に引っ掛かっているためである。

The index key prefix length limit is 3072 bytes for InnoDB tables that use DYNAMIC or COMPRESSED row format.

※ デフォルトではDYNAMIC row formatである。

utf8mb4では1文字4バイトなので、インデックスのキーの長さが合計768文字まで許されるはずである。合計768文字に制限した以下のSQLは成功して、テーブルが作成される。(この例では2つの列ぞれぞれで先頭384文字をキーとして使用するよう設定している。)

mysql> CREATE TABLE testtable (
    ->     id INT PRIMARY KEY,
    ->     text1 VARCHAR(2000),
    ->     text2 VARCHAR(2000),
    ->     UNIQUE (text1(384), text2(384))
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.04 sec)

また、実際に確認してみると、インデックスが作成されている。

mysql> show index from testtable;
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table     | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| testtable |          0 | PRIMARY  |            1 | id          | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| testtable |          0 | text1    |            1 | text1       | A         |           0 |      384 |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| testtable |          0 | text1    |            2 | text2       | A         |           0 |      384 |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
3 rows in set (0.01 sec)

疑問点

ここまで来て疑問に思ったのは、ユニークであるかどうかの判断は、INSERTしようとしているその列の値全てではなく、ユニークインデックスのキーの長さの部分によって判断されるのではないかということである。机上で調査したが確証は得られなかったので、実機で試してみることにした。

試行

環境

Ubuntu 20.04.1 LTSおよびMySQL 8.0.22である。

stack@stack:~$ lsb_release -d
Description:    Ubuntu 20.04.1 LTS
stack@stack:~$ mysql --version
mysql  Ver 8.0.22-0ubuntu0.20.04.2 for Linux on x86_64 ((Ubuntu))
stack@stack:~$ mysqld --version
/usr/sbin/mysqld  Ver 8.0.22-0ubuntu0.20.04.2 for Linux on x86_64 ((Ubuntu))

試行結果

以下が試行結果である。
ユニークであるかどうかの判断は、ユニークインデックスのキー長によって決まり(今回の場合はtext1が5character、text2が5character)、その長さより後の文字は重複しているかどうかの判断では用いられないようである。

mysql> CREATE TABLE shorttable (
    ->     id INT PRIMARY KEY,
    ->     text1 VARCHAR(2000),
    ->     text2 VARCHAR(2000),
    ->     UNIQUE (text1(5), text2(5))
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT shorttable values (1, 'AAAAAAAAAA', 'BBBBBBBBBB');
Query OK, 1 row affected (0.01 sec)

mysql> INSERT shorttable values (2, 'AAAAA=====', 'BBBBB@@@@@');
ERROR 1062 (23000): Duplicate entry 'AAAAA-BBBBB' for key 'shorttable.text1'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

諦めないのが俺の魔法だ!!絶対にリモートサーバーからDB情報を取得してインポートしてみせる!!

案件の保守対応で環境構築の際に
DB情報を用意されておらず
開発で利用していたサーバーから
DB情報を取ってきてローカルで反映させるために
今回行った内容を忘備録としてまとめておく。

余談ですが、ガチの現役エンジニアは本当にすごい
相談でちょいと質問したら悩んでいる原因を明確化(整頓)してもらった上で
回答を貰える
答えを教えるのは悪!とは言いませんが
考えもせずに答えを教えて貰うのと
なぜ悩んでいるのかを明確にしてもらってから教えてもらうとでは
理解度と腹落ち度が断然変わってきますね(о´∀`о)

それでは本題へ!

リモートサーバーのDB情報が欲しい

まずはリモートサーバーへログイン
sshで〜のくだりは別途調べてみて下さい!
ログインできたら次に
MySQLへのログインをして求めているDB情報があるのか確認をしよう!

$ mysql -u ユーザ名 -p

上記を入力してEnterを押すと
パスワードが求められるので入力してEnter
ログインができると[$]が[mysql>]に変わるのでそうなれば成功

mysql>

次にDB情報を一覧で確認する

mysql> show tables;

すると一覧で表示されるのでそのDBの名前を控えておく
もし必要であればテーブル情報も確認できるので参考にしてみて下さい

mysql> use db_name;
mysql> show tables;

そしたら次はそのテーブル情報をファイルにしていきます

mysql> quit //またはexit
mysql> show tables;

MySQLから抜けることが必要です!
自分はこれを知らずに
ずっとMySQL内でdumpしようとしてエラー出しまくってました
抜けたら次に

$ mysqldump -u USER_NAME -p -h HOST_NAME DB_NAME > OUTPUT_FILE_NAME

それぞれの必要項目が間違っていなければ
このコマンドを入力した階層内でファイルが作成されます

ここまででリモートサーバーでの作業は終わりなのですが
出る前に求めているファイルのパスだけ確認しておくとあとの作業が楽になりますね

ローカルでの作業

ローカルであればどこでもいいと思うのですが僕は今回デスクトップに
ファイルをダウンロードしてくる操作をしました

$ scp [オプション] [接続ユーザ]@ホスト名(IPアドレス):コピー元 コピー先

それぞれの情報を理解しておけばこちらもさくっと打って
ダウンロードができます!
終わったらDBをインポートさせるんですが
僕は今回、Sequel Proを使ってインポートをしたのですが
順番を間違えるとあれ?できない??ってなるので気をつけましょう!

  • まずはDBを作っておく
  • 作ったDBを選択しておく
  • インポートが活性化されるので指定のファイルをインポート

これで今回求めていた作業が完了しました!
覚えてしまえば10前後で終えれそうな内容でしたね
ちなみに僕は1時間前後かかってましたので
時間を無駄にしないように気をつけましょう(о´∀`о)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【いくつ知ってる?】MySQLでCRUD操作のクエリまとめ【超基本】



最近MySQLにどっぷり浸かって学習しているのですが、ある程度知識のストックもできたのでアウトプットがてら、超基本的なCRUD操作のクエリについて、まとめて行きたいと思います。


目次

  • CRUDについて
  • Create
  • Read
  • Update
  • Delete


CRUDについて

まず初めに、CRUD(クラッド)とは目次でも書きましたが、

  • Create(作成)
  • Read(参照)
  • Update(更新)
  • Delete(削除)

と言う、Webサービスなどで最も基本的な機能の事を指します。

例えばツイッターなんかでも、ツイートを作成し、それをフォロワーなどが見る(参照)ことができます。そして、プロフィールなどの部分を随時更新する事ができ、不要なツイートやアカウントは削除する事ができます。

このような基本的な機能の事を総称して生まれたのが、CRUDと言う言葉になります。次からは、このCRUD操作をMySQLのクエリでどのように行っていくのかを、説明していこうと思います。



Create

CREATE句

-- EXampleデータベースを作成。
CREATE DATABASE EXample;

-- Exampleテーブルの作成。
CREATE TABLE Example
  (
        id INT(10) not null auto_increment primary key,
        name VARCHAR(255) not null,
        age INT(3)
  );

テーブルの作成について、細かい事は省きますが、括弧の中は1行につき、1カラム(縦列)の設定を行っています。表で書くとこんな感じですね。

id name age



INSERT句

-- Exampleテーブルにレコードを追加。
INSERT INTO Example VALUES (1, "Abe", 32);

レコード(横列)の作成(追加)。カラムの並びに応じて、カンマ区切りでデータを記述します。実行後はこんな感じですね。

id name age
1 Abe 32


複数行を一気にいれる場合はこちら。

-- Exampleテーブルに複数レコードを追加。
INSERT INTO Example VALUES
        (2, "Ide", 37),
        (3, "Hide", 21);

実行後はこんな感じです。

id name age
1 Abe 32
2 Ide 37
3 Hide 21





Read

SHOW句

-- データベースの一覧
SHOW DATABASES;

-- テーブルの一覧
SHOW TABLES;

-- Exampleテーブルのカラム情報一覧
SHOW COLUMNS FROM Example;

個人的にはテーブルの一覧を確認する事が多いですね。ECサイトのDBとかになるとテーブルが10個近くあったりするので、いちいち覚えてられません。(笑)



SELECT句

-- Exampleテーブルの全カラムを取得。
SELECT * FROM Example;

-- Exampleテーブルのnameカラムを取得。
SELECT name FROM Example;

-- Exampleテーブルのidカラム、nameカラムを取得。
SELECT id, name FROM Example;

最も基本的なSELECT句の使い方です。全カラム情報の取得なんかは、よく使います。



WHERE句

-- Exampleテーブルで、ageが32の全カラムを取得。
SELECT * FROM Example WHERE age = 32;

WHERE句は主に条件指定をする際に使用します。情報を取得する時は、条件を絞って取得することがほとんどなので、こちらは超頻出ですね。

実行して取得できるのは、こんな感じですね。

id name age
1 Abe 32





Update

UPDATE句

-- Exampleテーブルでageカラムを、全て50に変更。
UPDATE Example SET age = 50;

-- Exampleテーブルでidが1のageカラムを、50に変更。
UPDATE Example SET age = 50 WHERE id = 1;

使うのは下の方ですね。特定のレコードの情報を更新したい時なんかに使用。あと紹介しといてあれですが、上はほぼ使わないです。(笑)





Delete

DELETE句

-- Exampleテーブルの全レコードを削除。(テーブル自体は残る)
DELETE FROM Example;

-- Exampleテーブルの id=1 に一致したレコードを削除。
DELETE FROM Example WHERE id=1;

こちらも使うのは下の方ですね。上は実行しようとすると、逆にセーフティ設定で弾かれることがあります。



DROP句

-- Exampleテーブルをオブジェクトごと完全に削除。
DROP TABLE Example;

-- EXampleデータベースの削除。
DROP DATABASE EXample;

こちらは不要になったテーブルやデータベースを削除したい時に使いますね。ただ、一度構築して運用を始めたら、余程の事がない限りは使わないかと。





まとめ

基本的なCRUD操作は、以上の内容である程度できるかと。ただ、SELECT句に関しては、WHERE句以外にも使えるクエリが沢山あります。(曖昧な検索をするLIKE句など)

気になる方は是非、本格的に学習してみてください!

最後まで読んでいただき、ありがとうございました!





筆者:yuki|学習10日目で初案件獲得→現在はフルスタックエンジニア転職に向けて学習中
Qiita:https://qiita.com/yuki4839
Twitter:https://twitter.com/yuki35522891

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

途中でDBを変更する方法

gemにある既存のDBを変更

$ bundle install


config/database.ymlにある既存のDBを変更

$ rake db:create
$ rake db:migrate
== 20201120000030 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.1683s
== 20201120000030 CreateUsers: migrated (0.1690s) =============================

== 20201120004112 AddIndexToUsersEmail: migrating =============================
-- add_index(:users, :email, {:unique=>true})
   -> 0.1129s
.
.
.
.

完了。

一言: gemファイルだけ変更すればいいと思っていました。database.ymlも変更する必要があると知りました。

参考:
https://stackoverflow.com/questions/52477636/gemloaderror-error-loading-the-sqlite3-active-record-adapter
https://qiita.com/pchatsu/items/a7f53da2e57ae4aca065

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GO gorm DB作成 INSERT JSONUnmarshal Mysql

こんにちは! GO学習中です!

今回はgormでinsertしてみたいと思います!

データは前回getしたapi
のデータを使用します。

DB自体をGOから作成した記事はこちらです。

では始めていきたいと思います。

mysql.go

// root/app/models/fgi.go
package mysql

import (
    "database/sql"

    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
)

// SQLConnect DB接続
func SQLConnect() (database *gorm.DB, err error) {
    DBMS := "mysql"
    USER := "root"
    PASS := ""
    PROTOCOL := "tcp(localhost:3306)"
    DBNAME := "テーブル名"

    CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?charset=utf8&parseTime=true&loc=Asia%2FTokyo"
    return gorm.Open(DBMS, CONNECT)
}

ここではDBはすでに作成しているものとします。
gormとはGOのORMパッケージです。

SQLConnect()の関数ではDBの情報を宣言して、

return gorm.Open(DBMS, CONNECT)

とすることでdbと接続しています。
DB情報はConfigなどにまとめたほうが良いかもしれません。今回はルートユーザーで行なっていきます。

fgi/fgi.go

こちらは冒頭紹介した記事
でgetしているapiのファイルです。上記の記事ではgetしただけでしたが、こちらでは
json.Unmarshalをすることで、用意した構造体に格納しています。

構造体はこちらの json-to-go
というサイトで簡単に用意できます。

左側にapiのjsonを貼り付けるとコード内のstructを用意してくれます。

package fgi

import (
    "encoding/json"
    "io/ioutil"
    "log"
    "net/http"
)

// APIClientFgi api情報格納
type APIClientFgi struct {
    key        string
    host       string
    httpClient *http.Client
}

// New struct生成
func New(key, host string) *APIClientFgi {
    fgiClient := &APIClientFgi{key, host, &http.Client{}}
    return fgiClient
}

// StructFgi fgi格納
type StructFgi struct {
    Fgi struct {
        Current struct {
            Value     int    `json:"value"`
            ValueText string `json:"valueText"`
        } `json:"now"`
        PreviousClose struct {
            Value     int    `json:"value"`
            ValueText string `json:"valueText"`
        } `json:"previousClose"`
        OneWeekAgo struct {
            Value     int    `json:"value"`
            ValueText string `json:"valueText"`
        } `json:"oneWeekAgo"`
        OneMonthAgo struct {
            Value     int    `json:"value"`
            ValueText string `json:"valueText"`
        } `json:"oneMonthAgo"`
        OneYearAgo struct {
            Value     int    `json:"value"`
            ValueText string `json:"valueText"`
        } `json:"oneYearAgo"`
    } `json:"fgi"`
}

// GetFgi api実行
func (fgi *APIClientFgi) GetFgi() (StructFgi, error) {

    url := "https://fear-and-greed-index.p.rapidapi.com/v1/fgi"

    req, _ := http.NewRequest("GET", url, nil)

    req.Header.Add("x-rapidapi-host", fgi.host)
    req.Header.Add("x-rapidapi-key", fgi.key)

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        return StructFgi{}, nil
    }

    defer res.Body.Close()

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        return StructFgi{}, nil
    }

    var fgiStruct StructFgi
    if err := json.Unmarshal(body, &fgiStruct); err != nil {
        log.Fatal(err)
    }

    return fgiStruct, nil
}

json-to-goで生成したstructを呼び出しjson.Unmarshalでstructに格納しています。

models/fgi.go

このファイルでは上記でstructに格納したapi情報を展開してDBにINSERTしていきます。

package models

import (
    "fmt"
    "index-indicator-apis/mysql"
    "time"

    "index-indicator-apis/config"
    "index-indicator-apis/fgi"
)

const (
    tableNameFgis = "fgis"
)

// Fgis 日足格納
type Fgis struct {
    CreatedAt time.Time `json:"created_at,omitempty"`
    NowValue  int       `json:"now_value,omitempty"`
    NowText   string    `json:"now_text,omitempty"`
    PcValue   int       `json:"pc_value,omitempty"`
    PcText    string    `json:"pc_text,omitempty"`
    OneWValue int       `json:"one_w_value,omitempty"`
    OneWText  string    `json:"one_w_text,omitempty"`
    OneMValue int       `json:"one_m_value,omitempty"`
    OneMText  string    `json:"one_m_text,omitempty"`
    OneYValue int       `json:"one_y_value,omitempty"`
    OneYText  string    `json:"one_y_text,omitempty"`
}

//initFgis マイグレーション
func initFgis() {
    var err error
    db, err := mysql.SQLConnect()
    if err != nil {
        panic(err.Error())
    }
    defer db.Close()
    db.AutoMigrate(&Fgis{})
}

// NewFgis fgi.StructFgiを受け取り、Fgisに変換して返す


func NewFgis(f fgi.StructFgi) *Fgis {
    createdAt := time.Now()
    nowValue := f.Fgi.Current.Value
    nowText := f.Fgi.Current.ValueText
    pcValue := f.Fgi.PreviousClose.Value
    pcText := f.Fgi.PreviousClose.ValueText
    oneWValue := f.Fgi.OneWeekAgo.Value
    oneWText := f.Fgi.OneWeekAgo.ValueText
    oneMValue := f.Fgi.OneMonthAgo.Value
    oneMText := f.Fgi.OneMonthAgo.ValueText
    oneYValue := f.Fgi.OneYearAgo.Value
    oneYText := f.Fgi.OneYearAgo.ValueText

    return &Fgis{
        createdAt,
        nowValue,
        nowText,
        pcValue,
        pcText,
        oneWValue,
        oneWText,
        oneMValue,
        oneMText,
        oneYValue,
        oneYText,
    }
}

// Create NewFgisをsaveする
func (f *Fgis) Create() error {
    db, err := mysql.SQLConnect()
    if err != nil {
        panic(err.Error())
    }
    defer db.Close()
    db.Create(&f)
    return err
}

// CreateNewFgis migration後にapiを叩きdbに保存する
func CreateNewFgis() error {
    // initFgis() migration
    fgiClient := fgi.New(config.Config.FgiAPIKey, config.Config.FgiAPIHost)
    f, err := fgiClient.GetFgi()
    if err != nil {
        return err
    }
    fgi := NewFgis(f)
    fmt.Println(fgi)
    fmt.Println(fgi.Create())
    return err
}

initFgis()ではgormのメソッドをつかってマイグレーションしています。
apiの情報を先ほどstructに格納したので、それを展開してさらに展開したvalueを格納するstructを用意するということですね。
db.AutoMigrate(&Fgis{}) こちらがgormのメソッド AutoMigrateメソッドです。
事前に用意した構造体の名前をテーブル名としてマイグレーションしてくれます。この場合だと
fgisというテーブルがmysqlに作成されます。

func NewFgis(f fgi.StructFgi) *Fgis{}
こちらではapiのデータを格納している StructFgiの中身を展開してINSERTするために用意した構造体(マイグレーションした)の中に格納してます。

func (f *Fgis) Create() error {}
こちらのメソッドではmysqlファイルで作成した関数のSQLConnect()でdbと接続後に

db.Create(&f)
とすることでINSERTを実現しています。 .Createがgormのメソッドです。 .Create(&struct)とすることでテーブル名と対応しているstructの情報をINSERTしてくれます。

最後にCreateNewFgis()で用意した関数とメソッドを実行しています。

この関数をmain.goから呼び出せば無事に実行されることができました。

  • gormでは主キーとなるIDは自動で生成されるので宣言する必要はありません。

以上です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む