自己写:把开头匹配改成取一段

👁️ 0 人浏览 💬 0 人评论 ❤️ 添加收藏

把下面的 TODO 改写成用范围表示"以 g1 开头"的写法,打出改写后判了多少次

两张表
goods  400 行   id 主键|sup_id 1~20|cat 只有 A/B/C|price = i*7%500|name "g1"~"g400"
sup     20 行   id 主键|city 杭州/苏州/南京/合肥(杭州 5 家)|name "s1"~"s20"

五个现成的工具函数(题面里已经写好)
plan(sql)      → 执行计划的每一行(一条查询可能有好几行)
first(sql)     → 只取第一行的第一个词:SCAN 还是 SEARCH
sortstep(sql)  → 有没有为排序/分组额外搭架子;有的话是为了哪一句
usedindex(sql) → 计划第一行用上的是哪一份索引
counted(sql)   → 数出这条查询把条件判了多少次(条件里要放 tick())
import sqlite3
db = sqlite3.connect(":memory:")
db.execute("CREATE TABLE sup (id INTEGER PRIMARY KEY, city TEXT NOT NULL, "
           "name TEXT NOT NULL)")
db.execute("CREATE TABLE goods (id INTEGER PRIMARY KEY, sup_id INTEGER NOT NULL, "
           "cat TEXT NOT NULL, price INTEGER NOT NULL, name TEXT NOT NULL)")
CITY = ["杭州", "苏州", "南京", "合肥"]
db.executemany("INSERT INTO sup VALUES (?,?,?)",
               [(i, CITY[i % 4], "s" + str(i)) for i in range(1, 21)])
db.executemany("INSERT INTO goods VALUES (?,?,?,?,?)",
               [(i, i % 20 + 1, "ABC"[i % 3], i * 7 % 500, "g" + str(i))
                for i in range(1, 401)])
db.commit()

def plan(sql):
    """把执行计划一行一行打出来(每行开头那个词就是取数方式)。"""
    return [r[3] for r in db.execute("EXPLAIN QUERY PLAN " + sql)]

def first(sql):
    """只要计划第一行的第一个词:SCAN(扫过去)还是 SEARCH(定点找)。"""
    return plan(sql)[0].split()[0]

def sortstep(sql):
    """有没有为了排序/分组**额外搭一次架子**?有的话是为了哪一句。"""
    for line in plan(sql):
        if "TEMP B-TREE" in line:
            return line.split("FOR ")[1].replace(" ", "")
    return "没有"

def usedindex(sql):
    """计划第一行用上的是哪一份索引(没用上就是"没有")。"""
    head = plan(sql)[0]
    if "INDEX " not in head:
        return "没有"
    return head.split("INDEX ")[1].split(" ")[0]

def counted(sql):
    """数一数这条查询把条件判了多少次。
    ⚠️ tick() 必须写在条件的最前面:写在后面时它只对已经匹配上的行求值,
       数出来的就变成"结果有几行",而不是"过了几行"。"""
    hits = {"n": 0}
    db.create_function("tick", 0, lambda: hits.__setitem__("n", hits["n"] + 1) or 1)
    db.execute(sql).fetchall()
    return hits["n"]
db.execute("CREATE INDEX ix_name ON goods(name)")
# 原来的写法:SELECT * FROM goods WHERE name LIKE 'g1%'
q = "SELECT * FROM goods WHERE tick() AND name LIKE 'g1%'"
# TODO:改写成 name >= ... AND name < ... 的范围写法
print(counted(q))
提交你的答案
请登录后提交答案。
去登录
代码编辑器
Ctrl + Enter 运行
本次输入:
输出:

                        
👩‍🏫
AI
💬 题目评论

全部评论