SQL Alchemy 插入到 table,列是从另一个 table 中选择的

SQL Alchemy insert into table, with column being selected from another table

我有以下 tables,我想看看我是否可以执行插入,其中对于每个插入的行,链接列的值由另一个使用 SQL炼金术和插入功能。 table 是:

from sqlalchemy import MetaData, Table, Column, Integer, VARCHAR, ForeignKey, create_engine

SQL_ENGINE = create_engine(...)

metadata_obj = MetaData(bind=SQL_ENGINE, schema="collections")
flows = Table(
    "flows", metadata_obj,
    Column("id", Integer, autoincrement=True, primary_key=True),
    Column("voyage_name", VARCHAR(100), nullable=False, unique=True),
    Column("vessel_name", VARCHAR(length=100), nullable=True, unique=False),
    Column("origin_country_id", Integer, ForeignKey("metadata.tbl_country.id"), nullable=True,
           unique=False),
    Column("destination_country_id", Integer, ForeignKey("metadata.tbl_country.id"),
           nullable=True, unique=False))
country = Table(
    "country", metadata_obj,
    Column("id", Integer, autoincrement=True, primary_key=True),
    Column("country_name", VARCHAR(100), nullable=False, unique=False),
    Column("country_iso", VARCHAR(2), nullable=False, unique=False)
)    

当我提取值时,我得到以下数据作为 pandas 数据帧:

voyage_name vessel_name origin_country_iso destination_country_iso
voyagename1 vesselname1 US GB
voyagename2 vesselname2 BR FR
voyagename3 vesselname3 NL CY

我想将其插入到我的流程中 table。然后,我将上面的数据框转换为如下所示的字典列表:

insert_data = [
    {
        "voyage_name": "voyagename1",
        "vessel_name": "vesselname1",
        "origin_country_iso": "US",
        "destination_country_iso": "GB"
    },
    {
        "voyage_name": "voyagename2",
        "vessel_name": "vesselname2",
        "origin_country_iso": "BR",
        "destination_country_iso": "FR"
    },
    {
        "voyage_name": "voyagename3",
        "vessel_name": "vesselname3",
        "origin_country_iso": "NL",
        "destination_country_iso": "CY"
    }
]

如果写在 SQL 中,我可以执行以下操作将数据上传到我的流程中 table:

INSERT INTO flows (
    voyage_name,
    vessel_name,
    origin_country_id,
    destination_country_id
)
VALUES
    ('voyagename1', 'vesselname1', 
     (SELECT id FROM country WHERE country_iso = 'US'), (SELECT id FROM country WHERE country_iso = 'GB')
    ),
    ('voyagename2', 'vesselname2', (SELECT id FROM country WHERE country_iso = 'BR'), 
     (SELECT id FROM country WHERE country_iso = 'FR')
    ),
    ('voyagename1', 'vesselname3', 
     (SELECT id FROM country WHERE country_iso = 'NL'), (SELECT id FROM country WHERE country_iso = 'CY')
    )

我如何使用 SQLalchemy 和插入语句执行等效的插入语句,并使用我的字典提供的值?

from sqlalchemy.dialects.postgresql import insert
flows_insert_stmt = insert(flows).values(insert_data)

注意:数据库是 PostgreSQL。

假设您已经拥有该国家/地区的所有 iso 值table并且没有遗漏,构造此类查询语句的一种方法如下

from sqlalchemy import insert, select

for row in insert_data:
    stmt = insert(flows).values(
        voyage_name=row['voyage_name'],
        vessel_name=row['vessel_name'],
        origin_country_id=select(country.c.id).where(country.c.country_iso==row['origin_country_iso']).scalar_subquery(),
        destination_country_id=select(country.c.id).where(country.c.country_iso==row['destination_country_iso']).scalar_subquery(),
    )
    print(stmt)

此脚本生成的语句是:

INSERT INTO collections.flows (voyage_name, vessel_name, origin_country_id, destination_country_id) VALUES (%(voyage_name)s, %(vessel_name)s, (SELECT collections.country.id 
FROM collections.country 
WHERE collections.country.country_iso = %(country_iso_1)s), (SELECT collections.country.id 
FROM collections.country 
WHERE collections.country.country_iso = %(country_iso_2)s)) RETURNING collections.flows.id

使用scalar_subquery是强制一值结果