美文网首页
django中使用原生sql的CASE WHEN语句

django中使用原生sql的CASE WHEN语句

作者: 小狐濡尾 | 来源:发表于2015-11-05 17:16 被阅读1070次

    orm并非万能

    从功能集上讲,django的orm只是sql的一个子集。也就是说很多使用sql能实现的功能,django orm是无法完成的,更不用说sql甚至是图灵完备的了。比如,直到1.8中,django才逐渐实现了case,when,if这些控制流。而这些内容在一些特殊类型的表操作中非常常见,比如说报表管理。

    好在django提供了使用原生sql的接口,这样就能通过原生sql来实现一些复杂的功能。

    sql控制流之CASE WHEN一个例子

    现有一张档案信息表archives:

    屏幕快照 2015-11-05 下午4.41.32.png

    字段说明:

    • number 档案号
    • type 档案类型
    • status 档案状态
    • company 公司
    • branch_company 分公司

    需求是计算出表中同一type,同一分公司下的档案总数,和status=01的档案数,以及它占档案总数的比值。

    当然,使用编程语言也可以实现这个功能,但是会比较复杂。这个时候可以使用case when语句来精确控制表中同一字段下,不同内容的选择。

    SELECT 
          COUNT(CASE WHEN status='01' THEN status END) status_01,
          COUNT(*) total,
          CONCAT(FORMAT(COUNT(CASE WHEN status='01' THEN status END)/
          COUNT(*)*100, 2), '%')
    FROM
          archives
    GROUP BY
          status, subbranch_company
    

    这样就可以解决上面提出的问题,因为这个表是临时杜撰的,结果这里就不贴了。

    在上述基础上实现链式查询

    在django的orm中,一个非常好用的功能就是使用链式查询,你可以不断连接filter等方法来过滤出想要的内容。

    这在一些特定的场景中特别有用。比如在上面的表中,我有时候想要某个分公司或中支公司下的数据,有时候又想要单一类型下的数据。如果针对每一种条件组合分别写相应地sql查询的话,会非常复杂,而且有时候组合会特别多。而链式查询比较完美的解决了这个问题。
    而为了让原生sql也能有个简单的链式查询,我们需要不断连接where中的条件子句。为此可以写一个简单的类来实现它:

    class GenQuerySQL(object):
    
        def __init__(self, table):
            self.table = table
            self.group_by_fields = " "
            self.where_conditions = " 1=1 "
            self.fields = " "
            self.order_by_fields = ""
    
        def where(self, where_condition):
            if where_condition:
                self.where_conditions += " and " + where_condition
            return self
    
        def add_field(self, fields):
            self.fields += " " + fields
            return self
    
        def group_by(self, group_by_field):
            self.group_by_fields = group_by_field
            return self
    
        def order_by(self, order_by_field):
            self.order_by_fields = order_by_field
            return self
    
        def sql(self):
           SQL = 'SELECT ' + self.fields + ' FROM ' + self.table + ' WHERE ' + self.where_conditions + ' GROUP BY ' + self.group_by_fields + ' ORDER BY ' + self.order_by_fields +  ";"
           return SQL
    

    这个类可以简单的模拟链式查询的功能,可以这样使用它:

    archive_statistics = GenQuerySQL(SOME_TABLE)
    raw_sql = archive_statistics.add_field(fields).where(where_condition).group_by(group_by_fields).order_by(order_by_fields).sql()
    

    其中.where可以多次连接。当然也可以使用另一种方式:先把where语句根据条件构造完毕,最终再拼接成sql语句。其思想是一样的:先过滤条件,最终再查询数据库。

    相关文章

      网友评论

          本文标题:django中使用原生sql的CASE WHEN语句

          本文链接:https://www.haomeiwen.com/subject/mdcchttx.html