SQL SELECT DISTINCT文は、重複しない異なる値のみを返すために使用されます。

Customersテーブルから異なるすべての国を選択します:

SELECT DISTINCT Country FROM Customers;

テーブル内の列はしばしば多くの重複する値を含むことがありますが、異なる(重複しない)値のみをリストしたい場合があります。

構文


SELECT DISTINCT column1, column2, ...
FROM table_name;

デモデータベース

以下は例で使用されるCustomersテーブルからの一部です:

CustomerID CustomerName ContactName Address City PostalCode Country
1 Alfreds Futterkiste Maria Anders Obere Str. 57 Berlin 12209 Germany
2 Ana Trujillo Emparedados y helados Ana Trujillo Avda. de la Constitución 2222 México D.F. 05021 Mexico
3 Antonio Moreno Taquería Antonio Moreno Mataderos 2312 México D.F. 05023 Mexico
4 Around the Horn Thomas Hardy 120 Hanover Sq. London WA1 1DP UK
5 Berglunds snabbköp Christina Berglund Berguvsvägen 8 Luleå S-958 22 Sweden

DISTINCTなしのSELECT例

DISTINCTキーワードを省略すると、SQL文はCustomersテーブルのすべてのレコードから「Country」値を返します:

SELECT Country FROM Customers;

重複しないカウント

DISTINCTキーワードをCOUNT関数で使用することで、異なる国の数を返すことができます。

SELECT COUNT(DISTINCT Country) FROM Customers;

注:COUNT(DISTINCT column_name)はMicrosoft Accessデータベースではサポートされていません。

MS Access用の回避策はこちらです:


SELECT Count(*) AS DistinctCountries
FROM (SELECT DISTINCT Country FROM Customers);

GoogleサーチコンソールでURLがインデックス登録されているか確認してみた結果、

「ページはインデックスに登録されていません: 重複しています。ユーザーにより、正規ページとして選択されていません」と表示され、インデックス登録されていなかった場合、Googleによって指定したURLが正規のページと判断されなかったということになります。

正規のページとは、以下の2つのURLが存在した場合、かつ同じページ(構造やコンテンツが同一)を示している場合、Googleはどちらか一つのURLを優先し、その優先されたページが正規ページとなります。

Googleは自動で正確な情報、かつ有益と判断した方を正規ページとして扱うとありますが、必ずしもそれが管理者にとってふさわしい結果であるとは限りません。

そんな場合に管理者が明示的に特定のURLを正規ページとしてマークし、Googleに伝える方法を紹介します。

rel=”canonical” linkタグを使う

例えばhttps://example.com/dresses/green-dressesというURLを正規ページにしたいとします。しかし何らかの方法でこのページにたどり着くURLが複数個ある場合、以下の手順でこのURLを正規ページに指定することができます。

  1. 重複するページすべての<head>タグ内にrel=”canonical” linkタグを追加する。今回の場合、linkタグは以下のようになります。
<link rel="canonical" href="https://example.com/dresses/green-dresses" />
  1. 正規ページがデスクトップとモバイル版で違う場合はrel=”alternate” linkタグを追加してモバイル版の正規ページを指定する。
<link rel="alternate" media="only screen and (max-width: 640px)"  href="https://m.example.com/dresses/green-dresses">
  1. 他の重複ページを正規ページにリダイレクトさせるようにする。

以上です。

私の経験ではユーザーが指定した正規ページが100%Googleによって正規ページとして扱われるわけではありませんでしたが、明示的に正規ページを指定することにより、インデックス登録される可能性が少しは上がります。

Djangoで作成したモデルをobjects.filter()メソッド等で抽出した場合、

‘django.db.models.query.QuerySet’型のオブジェクトが返されます。

このQuerySetはテンプレート内でもviews.pyの中でもリストの用にして扱うことができます。
別々の条件でQuerySetを生成したけれど、一つのQuerySetとしてまとめて扱いたいという場合に複数のQuerySetを一つのQuerySetに結合する方法を解説します。

結論から言うと、unionメソッドを使うことで複数のQuerySetを結合することができます。以下ではunionメソッドの使い方を解説していきます。

前提

今回はnameとpriceをフィールドにもつProductというモデルを利用していきます。

Productは既に5つ用意してあり、それぞれをProduct.objects.all()で取得した結果をテンプレートから出力した結果が以下のようになっています。

all_products = Product.objects.all()
</table>
<hr>
<h2>Queryset_2</h2>
<table border="1">
    <thead>
        <tr>
            <th>name</th>
            <th>price</th>
        </tr>
    </thead>
    <tbody>
    {% for product in Queryset_2%}
    <tr>
        <td>{{product.name}}</td>
        <td>{{product.price}}</td>
    </tr>
    {% endfor %}
    </tbody>
</table>

union()で結合する

それではさっそくunionの使い方を説明していきます。

まずは結合する前のQuerySetが必要なので、Productモデルからpriceが300のものと500のものをそれぞれfilter()メソッドで抽出していきます。

それぞれをqueryset_1、queryset_2という変数に代入しておき、それらをunionでまとめたものをqueryset_3とします。

以下のコードで上記のことを行っています。

views.py

from django.shortcuts import render
from .models import Product
# Create your views here.
def result(request):
    all_products = Product.objects.all()
    queryset_1 = Product.objects.filter(price=300)
    queryset_2 = Product.objects.filter(price=500)
    queryset_3 = queryset_1.union(queryset_2)
    
    context = {
        'all_products': all_products,
        'queryset_1': queryset_1,
        'queryset_2': queryset_2,
        'queryset_3': queryset_3, 
    }
    
    return render(request, 'result.html', context)

result.html

<h2>全商品</h2>
<table border="1">
    <thead>
        <tr>
            <th>name</th>
            <th>price</th>
        </tr>
    </thead>
    <tbody>
    {% for product in all_products%}
    <tr>
        <td>{{product.name}}</td>
        <td>{{product.price}}</td>
    </tr>
    {% endfor %}
    </tbody>
</table>
<hr>
<h2>Queryset_1</h2>
<table border="1">
    <thead>
        <tr>
            <th>name</th>
            <th>price</th>
        </tr>
    </thead>
    <tbody>
    {% for product in queryset_1%}
    <tr>
        <td>{{product.name}}</td>
        <td>{{product.price}}</td>
    </tr>
    {% endfor %}
    </tbody>
</table>
<hr>
<h2>Queryset_2</h2>
<table border="1">
    <thead>
        <tr>
            <th>name</th>
            <th>price</th>
        </tr>
    </thead>
    <tbody>
    {% for product in Queryset_2%}
    <tr>
        <td>{{product.name}}</td>
        <td>{{product.price}}</td>
    </tr>
    {% endfor %}
    </tbody>
</table>
<hr>
<h2>Queryset_3(Queryset_1 + Queryset_2)</h2>
<table border="1">
    <thead>
        <tr>
            <th>name</th>
            <th>price</th>
        </tr>
    </thead>
    <tbody>
    {% for product in queryset_3%}
    <tr>
        <td>{{product.name}}</td>
        <td>{{product.price}}</td>
    </tr>
    {% endfor %}
    </tbody>
</table>

出力結果

まとめ

queryset_1.union(queryset_2)という構文で二つのQuerySetを一つにまとめることができます。

以下書籍を参考にしました。

最近Amazonのアソシエイトリンクを生成するためのProduct Advertisin API、通称PA-APIが5.0にアップデートされ、さまざまな機能が追加された。

その中の一つであるScratchpadはブラウザ上で簡単にAPIの動作を確認できるツールで、取得したい情報をブラウザ上で選択するだけで出力結果とコードを表示してくれる強力なツール。

今回はそのScratchpadについて基本的な使い方を紹介していこうと思う。

Scratchpadとは

ScratchpadはPA-APIにリクエストを送信し、結果を取得することができるツールであり、同時にいくつかのプログラミング言語でのサンプルコードも返してくれる。そのためPA-APIがどのように動作するのかを手軽に確認することができ、サンプルコードを自身のプロジェクトにそのまま組み込むこともできるため、コーディングの手間も大幅に省くことができる強力なツールである。

なお、使用するためにはPA-APIのアクセスキーとシークレットキーを事前に取得しておく必要がある。

Scratchpadの使い方

それでは早速Scratchpadの使い方を説明していく。下記手順に沿って進めていけばAmazon上の商品を特定のキーワードで検索したり、特定の商品の情報を取得することができる。APIのアクセスキーとシークレットキーは取得済みと仮定して進める。

1.Scratchpadを開く

まずはScratchpadを開いてみよう。https://webservices.amazon.com/paapi5/scratchpad/index.htmlから開くと下記のような画面が表示される。

次に左のSelect Option内のGetBrowseNodesをクリックする。

すると上画像のセクションが表示されるので、順に入力していく。

Marketplaceは日本のアマゾンの商品を紹介する場合はwww.amazon.co.jpを選択する。

Partner TypeはAssociatesを選択。

Partner Tagはアソシエイトセントラルにログインした際に右上に表示されるアソシエイトIDを入力すればよい。

Access KeyとSecret Keyは事前に取得しておいたものを入力。取得していない場合はアソシエイトセントラルのツール>Product Advertisin API>認証キーの管理より認証情報の追加をクリックして取得することができる。

2.商品情報を取得する

上記の内容の入力が済んだらあとは商品情報を取得するだけである。

Select OptionのItem内にGetValiationsGetItemsSearchItemsの3つがあるので、まずは特定の商品情報を取得するGetItemsの使い方を説明する。

GetItemsをクリックするとリクエストパラメーターを入力するセクションが現れるので、必要に応じて入力しよう。ItemIdsはASINのことで、一度に最大10個指定することができる。つまり1度のリクエストで最大10個の商品情報を取得することができる。Amazon PAAPIはリクエスト数に何らかの制限があるので、なるべく多くの商品情報を取得するためには同時に商品を指定するコードを組むように工夫する必要がある。

今回は使い方の確認なので、一つのASINを指定する。ASINはAmazon上の商品すべてに紐づけられた固有のIDで、商品ページ内に記述されている。例えばこのモバイルバッテリーであれば登録情報に記されたB019GNUT0CがASINである。

これを先ほどのItemIdsに入力する。

次にResourcesを選択する。Resourcesとは指定した商品のどの情報を取得したいかを指定するものである。商品名、生産者名、セールスランキング、画像URLなど、Amazon上にあるデータは大体取得できるようになっている。Select Allを選択することでとりあえずすべての情報を取得することができる。

個人的には情報の抽出については自身のプロジェクト内のコードで行えばいいと思っているので、わざわざここでフィルタリングする意味はないような気もするが、もしかしたら必要な情報のみを指定することでレスポンスとして受け取るデータ容量を削減し、ごくわずかではあるが処理速度が上がるかもしれない。

ここではひとまずSelect Allを選択する。

以上二つが必須パラメーターなので、あとは実行すれば指定した商品の情報がすべて取得される。

Add a new parameterには商品の状態を指定するConditionや、販売元を指定するMerchantなどがあるので、必要に応じて追加すると良い。

必須項目の入力が完了した状態でRun Requestボタンをクリックすると、さっそく指定した内容でリクエストが送信され、結果が表示される。HTMLとして表示された状態や、JSON、サンプルコードなどが即座に表示されるので、そのまま自分のプロジェクトに組み込むこともできる。

商品を検索する

上ではASINを指定して商品情報を取得したが、Amazonを普通に利用しているときのようにキーワードなどから商品を検索して、その情報を取得することもできる。

Select OptionのSearchItemsを選択する。

例のごとくリクエストパラメーターを入力する欄が現れるので、必要に応じて入力しよう。

操作方法に関しては上記で説明したGetItemsと同じなので、よく使われるパラメーターについてのみ簡単に説明する。

Keywords:検索したい商品のキーワードを指定する。(例:モバイルバッテリー

Resources:GetItemsと同じく、検索した商品のどんな情報が欲しいかを指定。決まってない場合はSelect Allにしておけば問題ない。

SearchIndex:商品のカテゴリを指定する。国によってカテゴリを指定するSearchIndexが異なるため、日本用のSearchIndexを調べて指定する必要がある。日本のSearchIndexは次のURLから確認できる。https://webservices.amazon.com/paapi5/documentation/locale-reference/japan.html

例えば検索する商品のカテゴリをスポーツ用品に絞りたい場合はSportsAndOutdoorsを指定する。

Add new parameterよりそのほかの条件も追加できるが、この三つが一番基本的でありよく使われるのではないだろうか。

そのほかのものについては需要がありそうであれば今後記事にする。

先日個人的にDjangoでプロジェクトを制作したので、herokuにデプロイしてみた。すると

上のForbidden (403) CSRF verification failedというエラーがPOST送信時に発生してしまうことが判明。

ローカルで実行していたときには発生しなかったものなので、原因を調べていくと、どうやら独自ドメインを設定したことによるCSRF認証エラーらしい。

意外と簡単に解決できたので、このエラーの解決方法を記録しておく。

結論

結論から述べると、settings.pyに以下を追加することでこのエラーを解消できる。

ALLOWED_HOSTS           = [ "sharebuy.net" ]
CSRF_TRUSTED_ORIGINS    = [ "https://sharebuy.net" ] #追加

ちなみに今回作成したプロジェクトというのはhttps://sharebuy.netでお名前.comでsharebuy.netというドメインを取得後、herokuにデプロイしたものと紐づけた。

しかしそのまま何もしないとdjango側で独自ドメインからのアクセス時にcsrfトークンが合っていたとしても見知らぬホストからのcsrf攻撃だと判定してしまうため、settings.pyに上記の二行を追加して、csrf攻撃でないことを教えてあげる必要がある。

ALLOWED_HOSTSには独自ドメインのみを記述し、CSRF_TRUSTED_ORIGINSには独自ドメインを含むURLそのものを追加する。なお、このCSRF_TRUSTED_ORIGINSはデフォルトでは記述されていないので、これごと追加する必要がある。

まとめ

HerokuにデプロイしたdjangoプロジェクトでPOST送信時にCSRF関連のエラーが発生したら、まずはsettings.pyを確認し、ALLOWED_HOSTSとCSRF_TRUSTED_ORIGINSを修正するとよい。

最後に宣伝にはなるが、今回作成(作成中)したhttps://sharebuy.netはAmazonの良い商品・悪い商品を手軽にシェアし、買い物ミスを防ぐためのサイトなので、よければ使ってみてほしい。

併せてサイトの見た目等でまだまだ修正の余地があるので、Web制作が得意で協力してやってもいいぞという方はぜひご連絡お待ちしております。

[itemlink post_id=”2041″]

基礎講座レベル1

変数の値の変更の仕方

次は既に定義した変数の値を変更してみましょう。変数の値は何度でも変更が可能なので、一度定義した変数を何度でも再利用することができます。

「変数名 = 新しい値」と書くことで、新しい値に変更することができます。変数を定義するときとまるっきり同じですね。

greeting = "Hello"
print(greeting)    #"Hello"が出力される
greeting = "こんにちは"
print(greeting)    #"こんにちは"が出力される

上のコードでは変数greetingの値をHello⇒こんにちはに変更しています。コードは上から下に順に実行されていくので、一つ目のprint(greeting)ではHelloが出力され、二つ目ではこんにちはが出力されるようになります。

既に定義された変数に数値を足す

数値を代入しておいた変数に新たに変数を足したい時があります。

そんなとき、変数の値は(もとの変数の値+足す値)となりますが、プログラミングの世界では以下のように記述することができます。

x = 5
x = x + 8
print(x)   #13

以前説明したように、プログラミングの世界での「=」と私たちが普段使う数学の「=」は意味が異なります。数学的に考えると、x = x + 8という式は間違っているように感じられますが、プログラミングの世界ではこれはもとの変数に新しい値を足して値を更新するということになります。

同様に引き算や掛け算、割り算でも同じように値を代入することができます。

x = 10
x = x - 2    #8
x = x * 5    #40
x = x / 10   #4

コードは上から順に実行されるので、xは10から始まり、2を引かれて8に、その8に5を掛けて40に…という風に変更されていきます。

また上のコードのようにある変数自身に値を足したり引いたりするといったコードは以下のように省略して記述することができます。以下のコードは上のコードとまるっきり同じ意味になります。

x = 10
x -= 2    #8
x *= 5    #40
x /= 10   #4

「=」の左隣に記号を書くことで、その変数に新しく値を足したり引いたりするという意味になるのです。これもよく使われるので覚えておきましょう。

問題

以下のコードに書き加えて、

①変数pointに150を足して変数pointを更新してください。

②変数pointの値を出力してください。

point = 300

答え

[expander_maker id=”1″ more=”答え” less=”非表示”]
point = 300
point += 150
print(point)

[解説]

ここでは省略形を用いていますが、point = point + 150でもOKです。

[/expander_maker]

次のステップは 文字列を連結させるです

[itemlink post_id=”2041″]