【问题标题】:sqlite3.OperationalError: no such table: main.sourcesqlite3.OperationalError:没有这样的表:main.source
【发布时间】:2018-08-18 14:31:57
【问题描述】:

我正在制作一个使用 Python Flask 和 Sqlite3 的 API。大多数都有效。具体来说:

  • 所有 GET 端点/SELECT 查询都有效
  • 两个 POST 端点/INSERT INTO 查询工作

但是,其余的 POST/INSERT INTO 不起作用。它们都有相同的 sqlite3.OperationalError 消息:

no such table: main.source

这很奇怪,因为没有一个查询使用名为“source”或“main.source”的表。我在execute 之前打印查询,并且尝试将查询复制/粘贴到 sqlite3 命令提示符中。当我这样做时,查询没有问题。

另一个奇怪的事情是所有的 INSERT INTO 查询都调用相同的函数来创建实际的查询(这反过来又调用该函数来运行查询......所有查询都使用其中大部分工作)。只有部分 INSERT INTO 会导致此错误。

一些可能有用的信息:

createdb.sql 的摘录

CREATE TABLE transactions (
  id INTEGER PRIMARY KEY,
  buyer INTEGER NOT NULL,
  seller INTEGER NOT NULL,
  amount INTEGER NOT NULL,
  currency VARCHAR(6) NOT NULL,
  fee INTEGER NOT NULL,
  source INTEGER NOT NULL,
  description TEXT NOT NULL,
  status VARCHAR(40) NOT NULL,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

插入该 Python 打印/在execute 中引发错误:

INSERT INTO transactions (status, fee, description, source, seller, currency, amount, buyer) VALUES ('initiated', '1', 'nada', '1', '2', 'USD', '1000', '1');

还有一些来自 Sqlite 提示的东西:

sqlite> .tables
conversations  sources        users        
messages       transactions   withdrawals
sqlite> SELECT id, description FROM transactions;
1|hella mulah
2|payback
3|woohoo
sqlite> INSERT INTO transactions (status, fee, description, source, seller, currency, amount, buyer) VALUES ('initiated', '1', 'nada', '1', '2', 'USD', '1000', '1');
sqlite> 
sqlite> SELECT id, description FROM transactions;
1|hella mulah
2|payback
3|woohoo
4|nada

作为参考,这里有一个 POST 命令,尽管使用了大部分相同的东西,但没有错误:

INSERT INTO users (session, balance, name, firebaseToken) VALUES ('ABCDEFG', '0', 'Mr Miyagi', 'ABCDEFG');

关于 SO 有很多类似的问题,但这就是它们不重复的原因:

我考虑过但排除的其他内容:

我相信这最终会成为某种愚蠢的混乱,但任何关于在哪里寻找的想法都将不胜感激。我也试过用谷歌搜索这个错误,但没有发现任何有用的信息。

---更多代码---

这是database.py

import sqlite3
import flask

import backend

def dict_factory(cursor, row):
    output = {}
    for idx, col in enumerate(cursor.description):
        output[col[0]] = row[idx]
    return output


def get_db():
    if not hasattr(flask.g, 'sqlite_db'):
        flask.g.sqlite_db = sqlite3.connect("/my/absolute/path/var/data.db"
        )
        flask.g.sqlite_db.row_factory = dict_factory
        flask.g.sqlite_db.execute("PRAGMA foreign_keys = ON;")
    return flask.g.sqlite_db


def query(query, args=(), islast=False):
    print(query) # this is where the print from before is
    cur = get_db().execute(query, args)
    rowvector = cur.fetchall()
    if islast:
        cur.close()
    return rowvector


@backend.app.teardown_appcontext
def close_db(error):
    if hasattr(flask.g, 'sqlite_db'):
        flask.g.sqlite_db.commit()
        flask.g.sqlite_db.close()

这是从 apiimpl.py 中选择的部分

QUERY_INSERT = "INSERT INTO"
QUERY_SELECT = "SELECT"
QUERY_UPDATE = "UPDATE"

def queryhelper(*args, **kwargs):
    sqltxt = None
    selectstr = None
    if kwargs["action"] == QUERY_INSERT:
        sqltxt = "{} {} ({}) VALUES ({});".format(
            QUERY_INSERT,
            kwargs["table"],
            ", ".join(["{}".format(x) for x in kwargs["cols"]]),
            ", ".join(["'{}'".format(x) for x in kwargs["vals"]]),
        )
        # pretty sure this next bit is not relevant but here it is anyway
        selectstr = "SELECT * FROM {} WHERE ROWID=(SELECT last_insert_rowid());".format(
            kwargs["table"],
        )
    elif kwargs["action"] == QUERY_SELECT:
        # not relevant
    elif kwargs["action"] == QUERY_UPDATE:
        # not relevant
    else:
        assert(kwargs["action"] in [QUERY_INSERT, QUERY_SELECT, QUERY_UPDATE,])
    try:
        rv = db.query(sqltxt) # this is where the error is thrown
        if selectstr:
            return db.query(selectstr)
        else:
            return rv
    except sqlite3.OperationalError as e:
        # this is where the error is caught
        return api_error("SQL error (1): {}", str(e), code=500)

def append(tablename, args):
    tabledata = TABLES().tablenamemap[tablename]
    print("tablename: " + tablename) # "tablename: transactions"
    # a bunch of error detection 
    rv = queryhelper(
        action=QUERY_INSERT,
        table=tablename,
        cols=args.keys(),
        vals=args.values(),
    )
    # not shown: potentially returning json.dumps(rv)
    return rv


def transactions_post(req):
    # a lot of stuff to turn req into validargs
    # printed validargs: {'status': 'initiated', u'fee': u'1', u'description': u'nada', u'source': u'1', u'seller': u'2', u'currency': u'USD', u'amount': u'1000', u'buyer': u'1'}
    return append("transactions", validargs)


@backend.app.route("/transactions", methods=["GET", "POST", "PUT"])
def transactions_route():
    return {
        "GET":  transactions_get,       # get list of transactions
        "POST": transactions_post,      # initiate a transaction
        "PUT":  transactions_put,       # change transaction status
    }[flask.request.method](flask.request)

附:这个问题的目的不是讨论实现,而是如果你想发表评论,我可以。

---回应评论--

sqlite> SELECT * FROM sqlite_master WHERE type="table" AND name="transactions";
table|transactions|transactions|4|CREATE TABLE transactions (
  id INTEGER PRIMARY KEY,
  buyer INTEGER NOT NULL,
  seller INTEGER NOT NULL,
  amount INTEGER NOT NULL,
  currency VARCHAR(6) NOT NULL,
  fee INTEGER NOT NULL,
  source INTEGER NOT NULL,
  description TEXT NOT NULL,
  status VARCHAR(40) NOT NULL,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (buyer) REFERENCES users(id), -- do not want to delete on CASCADE
  FOREIGN KEY (seller) REFERENCES users(id), -- do not want to delete on CASCADE
  FOREIGN KEY (source) REFERENCES source(id) -- do not want to delete on CASCADE
)

【问题讨论】:

  • 如果你运行这个查询'SELECT * FROM sqlite_master WHERE type="table" AND name="transactions";'会得到什么。你是使用 sqlalchemy 还是直接使用 sqlite3 数据库适配器?
  • @bigjake 编辑了问题以包含响应。另外,我以为有人要求更多代码,所以我添加了它。我直接使用 sqlite3
  • if kwargs["action"] == QUERY_INSERT: 这转化为 if kwargs["action"] == "INSERT INTO" 还是我遗漏了什么?
  • @LAS 是的,我认为这是正确的。当我打印以 INSERT INTO 开头的查询时,您可以告诉 bc
  • @sudorm-rfslash 这个主键应该是“FOREIGN KEY (source) REFERENCES source(id) -- 不想在 CASCADE 上删除”引用 source(id) 还是来源?

标签: python flask sqlite


【解决方案1】:

根据您的 .tables 命令,您似乎正在引用一个不存在的表。

sqlite> .tables
conversations  sources        users        
messages       transactions   withdrawals

还有这个创建表语句。

CREATE TABLE transactions (
  id INTEGER PRIMARY KEY,
  buyer INTEGER NOT NULL,
  seller INTEGER NOT NULL,
  amount INTEGER NOT NULL,
  currency VARCHAR(6) NOT NULL,
  fee INTEGER NOT NULL,
  source INTEGER NOT NULL,
  description TEXT NOT NULL,
  status VARCHAR(40) NOT NULL,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (buyer) REFERENCES users(id), -- do not want to delete on CASCADE
  FOREIGN KEY (seller) REFERENCES users(id), -- do not want to delete on CASCADE
  FOREIGN KEY (source) REFERENCES source(id) -- do not want to delete on CASCADE
                               -- ^ there is no source table
)

如果您将 source(id) 更改为 sources(id),您应该会很好。

【讨论】:

  • 这里真正的教训是在运行创建脚本之前设置外键。我应该在 CREARE TABLE 中遇到错误
  • @sudorm-rfslash 更容易记住,当您使用完整的 RDBMS(如 Mysql、Postgres 和一些花哨的图形工具包(如 PHPMyAdmin 等)时)。当您使用 sqlite 并且您必须每次打开数据库时记得手动调用PRAGMA foreign_keys = ON;
猜你喜欢
  • 2021-04-10
  • 1970-01-01
  • 1970-01-01
  • 2015-07-30
  • 2016-02-20
  • 2022-01-21
  • 2021-07-24
  • 2017-09-12
  • 2017-12-10
相关资源
最近更新 更多