Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/85.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python SQLAlchemy:如何定义使用对包含该列的表的引用计算的列的默认值?_Python_Sql_Sqlalchemy - Fatal编程技术网

Python SQLAlchemy:如何定义使用对包含该列的表的引用计算的列的默认值?

Python SQLAlchemy:如何定义使用对包含该列的表的引用计算的列的默认值?,python,sql,sqlalchemy,Python,Sql,Sqlalchemy,SQLAlchemy:如何定义使用对包含该列的表的引用计算的列的默认值 让我们将这些表用作SQLite示例: CREATE TABLE department ( id INTEGER PRIMARY KEY, name TEXT NOT NULL ); CREATE TABLE employee ( id INTEGER, name TEXT NOT NULL, department_id INTEGER NOT NULL, FOREIGN KEY (departmen

SQLAlchemy:如何定义使用对包含该列的表的引用计算的列的默认值

让我们将这些表用作SQLite示例:

CREATE TABLE department (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL
);

CREATE TABLE employee (
  id INTEGER,
  name TEXT NOT NULL,
  department_id INTEGER NOT NULL,
  FOREIGN KEY (department_id) REFERENCES department(id),
  PRIMARY KEY (id, department_id)
);
我希望每个eployee的ID仅在其部门方面是唯一的。插入时,应生成一个新的员工ID,该ID比该部门以前最高的员工ID大一个

在原始SQL中,我希望执行以下操作:

INSERT INTO employee(
    id,
    name,
    department_id
)
VALUES (
    (
        SELECT coalesce(MAX(id),0)+1
        FROM employee
        WHERE department_id=?
    ),
    ?,
    ?
)
使用SQLAlchemy实现这一点的最佳方法是什么

我想我正在寻找类似于第三列示例的东西,比如:

employee_table = Table("employee", meta,
    Column('id', Integer, primary_key=True, autoincrement=False,
      default=keyvalues.select(
        func.max(employee_table.c.id)
      ).filter_by(department_id=??))
    Column('department_id', Integer, ForeignKey('department.id'),
        nullable=False, primary_key=True, autoincrement=False)
    Column('name', String(127), nullable=False),
    )
def __init__(self, department, name):
    self.id = db.select(
        db.func.max(Employee.id)
    ).filter_by(department_id=department.id).as_scalar()
    self.department = department
    self.data = data
当然,这是行不通的:我还没有对employee表的引用,因为我还在定义它,而且我不知道如何在filter\u by子句中引用当前的department\u id。很可能还有其他问题

或者,如果无法通过pythonapi实现这一点,是否可以使用原始SQL指定在插入时应用的列的默认值?还是需要对整个插入使用原始SQL

注意:我的情况与中基本相同,但我正在寻找的解决方案不同:我希望在插入中使用嵌套的SELECT,而不是创建DB触发器

编辑

我离解决这个问题越来越近了,但我还没有解决

sqlalchemy中的agronholm解释说,仅使用默认值无法填写部门id,因为尽管可以在插入时将可选项用作默认值,但无法填写部门id中的参数

相反,agronholm建议最好的解决方案是在构造函数中创建子查询。通过分配查询而不是运行查询并分配结果!,id将在子选择中获取。这避免了由于首先在Python端执行SELECT,然后分配结果而导致的竞争条件

我正在尝试这样的东西:

employee_table = Table("employee", meta,
    Column('id', Integer, primary_key=True, autoincrement=False,
      default=keyvalues.select(
        func.max(employee_table.c.id)
      ).filter_by(department_id=??))
    Column('department_id', Integer, ForeignKey('department.id'),
        nullable=False, primary_key=True, autoincrement=False)
    Column('name', String(127), nullable=False),
    )
def __init__(self, department, name):
    self.id = db.select(
        db.func.max(Employee.id)
    ).filter_by(department_id=department.id).as_scalar()
    self.department = department
    self.data = data
不幸的是,这也不起作用,因为计算列被用作主键的一部分。它抛出:

InvalidRequestError: Instance <XXXXX at 0x3d15d10> cannot be refreshed - it's not  persistent and does not contain a full primary key.

在原始SQLite版本中,我将使用光标的lastrowid访问新创建的行。SQLAlchemy中是否可能存在类似的问题?

我遇到了类似的问题,最终找到了这个解决方案。仍然有改进的余地-它在插入之前进行选择,而不是内联-但似乎有效

from sqlalchemy import sql

...

def default_employee_id(context):
    return context.connection.execute(
        sql.select(
            [sql.func.ifnull(sql.func.max(employee_table.c.id), 0) + 1]
        ).where(
            employee_table.c.department_id==context.current_parameters['department_id']
        )
    ).scalar()

employee_table = Table("employee", meta,
    Column('id', Integer, primary_key=True, autoincrement=False,
      default=default_employee_id),
    Column('department_id', Integer, ForeignKey('department.id'),
        nullable=False, primary_key=True, autoincrement=False),
    Column('name', String(127), nullable=False)
)
下一步我会尝试的是a,尽管文档说主键是个坏主意。 挂接到before_flush事件可能会有相同的预选问题。
也可以更改或替换context.compiled参数,以便将SELECT注入到INSERT中,但这对于我们试图实现的目标来说似乎是极端的。

unique on ID比unique on ID强,DeptID,您是否有理由希望多个不同的员工具有相同的员工ID,或者只是你不在乎他们是否在乎?我也在寻找解决办法。对我来说,你的方法行不通。在我的例子中,所讨论的列是主键的一部分,我收到错误消息:InvalidRequestError:Instance无法刷新-它不是持久的,并且不包含完整的主键。@room2web不幸的是,我遇到了相同的问题。我刚刚更新了这个问题。如果您找到解决方案,请向我们报告@IfLoop我应该注意到我只是以员工/部门为例。这可能不是最好的选择,因为员工ID几乎肯定是全球唯一的。真正的用例有点复杂:子表存储大量不同类别的对象,在这些类别之间迁移对象是没有意义的。虽然每个类别的ID仍然不是严格需要的,但我们希望它们主要是出于美观的原因:这些ID在RESTAPI/中是公开可见的,并且我们希望它们增加单位increments@GabrielGrant在IRC频道询问后,我将问题提交给了谷歌集团。希望他们能帮助我们。