2013-05-02 2 views
0

시퀀스를 생성해야하지만 일반적으로 Sequence 클래스를 사용하지 않습니다. 컬럼에 고유 한 일련 번호

USN = Column(Integer, nullable = False, default=nextusn, server_onupdate=nextusn) 

이 funcion nextusn 모델의 행 func.max(table.USN) 값을 생성 필요하다.

나는이

class nextusn(expression.FunctionElement): 
    type = Numeric() 
    name = 'nextusn' 

@compiles(nextusn) 
def default_nextusn(element, compiler, **kw): 
    return select(func.max(element.table.c.USN)).first()[0] + 1 

을 사용하려고하지만,이 맥락에서 요소 element.table을 모른다. 이 문제를 해결하기위한 기존 방법?

답변

0

이 이러한 이유로, 조금 까다 롭습니다 :

  1. 당신의 SELECT MAX() 테이블이 비어있는 경우 NULL을 반환한다; COALESCE를 사용하여 기본 "시드"값을 생성해야합니다. 아래를 참조하십시오.

  2. SELECT MAX를 사용하여 행을 삽입하는 모든 접근 방식은 동시 사용에는 전혀 안전하지 않으므로 한 번에 하나의 INSERT 문만 테이블을 호출하거나 제약 조건 위반이 발생할 수 있습니다 (확실히해야합니다. 이 열에 어떤 종류의 제약이 있음).

  3. SQLAlchemy의 관점에서 볼 때 실제 Column 요소를 인식하려면 사용자 지정 요소가 필요합니다. 우리는 사실 다음에 Column에 "nextusn()"함수를 할당하거나 이벤트를 사용하여보다 정교한 접근법을 보여줌으로써이 작업을 수행 할 수 있습니다.

  4. 나는 "server_onupdate = nextusn"으로 무엇을 할 것인지 이해하지 못합니다. SQLAlchemy의 "server_onupdate"는 실제로 SQL을 실행하지 않습니다. 예를 들어 트리거를 만든 경우에는 placeholder입니다. "SELECT MAX (id) FROM table"이 INSERT 패턴이기 때문에 UPDATE에서 어떤 일이 일어날 지 확신 할 수 없습니다.

  5. @compiles 확장자는 compiler.process()를 통해 select()를 실행하여 문자열을 반환해야합니다. 아래를 참조하십시오.

예 :

from sqlalchemy import Column, Integer, create_engine, select, func, String 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.sql.expression import ColumnElement 
from sqlalchemy.schema import ColumnDefault 
from sqlalchemy.ext.compiler import compiles 
from sqlalchemy import event 

class nextusn_default(ColumnDefault): 
    "Container for a nextusn() element." 
    def __init__(self): 
     super(nextusn_default, self).__init__(None) 

@event.listens_for(nextusn_default, "after_parent_attach") 
def set_nextusn_parent(default_element, parent_column): 
    """Listen for when nextusn_default() is associated with a Column, 
    assign a nextusn(). 

    """ 
    assert isinstance(parent_column, Column) 
    default_element.arg = nextusn(parent_column) 


class nextusn(ColumnElement): 
    """Represent "SELECT MAX(col) + 1 FROM TABLE". 
    """ 
    def __init__(self, column): 
     self.column = column 

@compiles(nextusn) 
def compile_nextusn(element, compiler, **kw): 
    return compiler.process(
       select([ 
        func.coalesce(func.max(element.column), 0) + 1 
       ]).as_scalar() 
      ) 

Base = declarative_base() 

class A(Base): 
    __tablename__ = 'a' 

    id = Column(Integer, default=nextusn_default(), primary_key=True) 
    data = Column(String) 

e = create_engine("sqlite://", echo=True) 

Base.metadata.create_all(e) 

# will normally pre-execute the default so that we know the PK value 
# result.inserted_primary_key will be available 
e.execute(A.__table__.insert(), data='single row') 

# will run the default expression inline within the INSERT 
e.execute(A.__table__.insert(), [{"data": "multirow1"}, {"data": "multirow2"}]) 

# will also run the default expression inline within the INSERT, 
# result.inserted_primary_key will not be available 
e.execute(A.__table__.insert(inline=True), data='single inline row') 
+0

답변 : 1. 예. 2. 예, 안전하지 않습니다. 나는 테이블을 가지고 시험해 본다. 시퀀스와 비슷합니다. 3. 예. 4. 나는 sqlalchemy에서 dummie이다. 5. 이제는 이해합니다. 이 행을 업데이트하는 데 문제가 있습니다. 테이블에 시퀀스를 유지할 방법을 연구 중입니다. 대답 해줘서 고마워요. – Jones