web-dev-qa-db-ja.com

SqlAlchemy:複数の列にわたる個別のカウント

できません:

>>> session.query(
        func.count(distinct(Hit.ip_address, Hit.user_agent)).first()
TypeError: distinct() takes exactly 1 argument (2 given)

できます:

session.query(
        func.count(distinct(func.concat(Hit.ip_address, Hit.user_agent))).first()

これは問題ありません(「pageload」データベーステーブル内の一意のユーザーの数)。

これは一般的なケースでは正しくありません。次の表では、2ではなく1のカウントが表示されます。

 col_a | col_b
----------------
  xx   |  yy
  xxy  |  y

次のSQLを生成する方法はありますか(少なくともpostgresqlで有効です)?

SELECT count(distinct (col_a, col_b)) FROM my_table;
14
EoghanM

Sqlalchemyのdistinct()は1つの列または式のみを受け入れるようです。

別の方法は、group_bycountを使用することです。これは、2つの列のconcatを使用するよりも効率的です。groupbyデータベースを使用すると、インデックスが存在する場合はインデックスを使用できます。

session.query(Hit.ip_address, Hit.user_agent).\
    group_by(Hit.ip_address, Hit.user_agent).count()

生成されたクエリは、あなたが尋ねたものとはまだ異なって見えます:

SELECT count(*) AS count_1 
FROM (SELECT hittable.user_agent AS hittableuser_agent, hittable.ip_address AS sometable_column2 
FROM hittable GROUP BY hittable.user_agent, hittable.ip_address) AS anon_1
8
vvladymyrov

distinct()は、クエリオブジェクトに追加されるときに複数の引数を受け入れます。

session.query(Hit).distinct(Hit.ip_address, Hit.user_agent).count()

次のようなものが生成されます。

SELECT count(*) AS count_1
FROM (SELECT DISTINCT ON (hit.ip_address, hit.user_agent)
hit.ip_address AS hit_ip_address, hit.user_agent AS hit_user_agent
FROM hit) AS anon_1

これはあなたが望んでいたものに少しでも近いです。

19
RedNaxel