【问题标题】:Pandas to_sql to add rows to database. Error: [ODBC SQL Server Driver] Invalid character value for cast specificationPandas to_sql 将行添加到数据库。错误:[ODBC SQL Server Driver] 转换规范的字符值无效
【发布时间】:2021-05-13 23:05:45
【问题描述】:

我想使用以下数据框将行插入 Microsoft SQL Server

new_companies = pd.DataFrame(columns=["Id","Name","CreatedDate","ModifiedDate","IsActive","No","SIMSId"])
# Insert two rows
new_companies = new_companies.append({
  "Id":999999,
  "Name":"Unknown",
  "CreatedDate": Timestamp('19010101'),
  "ModifiedDate": Timestamp('19010101'),
  "IsActive":0,
  "No":"999999",
  "SIMSId":""
}, ignore_index=True)
new_companies = new_companies.append({
  "Id":17,
  "Name":"Acme",
  "CreatedDate": Timestamp('20210228'),
  "ModifiedDate": Timestamp('20210228'),
  "IsActive":0,
  "No":"999999",
  "SIMSId":""
}, ignore_index=True)

new_companies.info()

# Output
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 7 columns):
 #   Column        Non-Null Count  Dtype         
---  ------        --------------  -----         
 0   Id            2 non-null      object        
 1   Name          2 non-null      object        
 2   CreatedDate   2 non-null      datetime64[ns]
 3   ModifiedDate  2 non-null      datetime64[ns]
 4   IsActive      2 non-null      object        
 5   No            2 non-null      object        
 6   SIMSId        2 non-null      object        
dtypes: datetime64[ns](2), object(5)
memory usage: 240.0+ bytes

然后我按以下方式创建数据库连接并尝试插入行:

import sqlalchemy

conn = sqlalchemy.create_engine("mssql+pyodbc://*myserver*/*mydatabase?trusted_connection=yes&driver=SQL+Server",echo=False,fast_executemany=True)

new_companies.to_sql('Companies',con=conn,if_exists='append',index=False)

我收到以下错误:

DataError: (pyodbc.DataError) ('22018', '[22018] [Microsoft][ODBC SQL Server Driver]Invalid character value for cast specification (0) (SQLExecute)')
[SQL: INSERT INTO [Companies] ([Id], [Name], [CreatedDate], [ModifiedDate], [IsActive], [No], [SIMSId]) VALUES (?, ?, ?, ?, ?, ?, ?)]
[parameters: ((999999, 'Unknown', datetime.datetime(1901, 1, 1, 0, 0), datetime.datetime(1901, 1, 1, 0, 0), 0, '999999', ''), (17, 'Acme', datetime.datetime(2021, 1, 28, 0, 0), datetime.datetime(2021, 1, 28, 0, 0), 0, '999', '0E581100-80E4-4024-86DF-072739F50FA8'))]

这是来自 SQL 管理工具的表定义

CREATE TABLE [dbo].[Companies](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
    [CreatedDate] [datetime2](7) NOT NULL,
    [ModifiedDate] [datetime2](7) NOT NULL,
    [IsActive] [bit] NOT NULL,
    [No] [nvarchar](10) NULL,
    [SIMSId] [uniqueidentifier] NULL,
 CONSTRAINT [PK_Companies] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

我很难诊断出这两个日期时间是问题所在(即我不确定它们是否是问题所在),但我希望有人可以帮助我诊断和解决问题。

【问题讨论】:

  • 我认为Timestamp('20210228') 是不可接受的,将其转换为字符串,例如2021-02-28
  • 您也可以显示表格定义吗?您还没有指定架构您正在写信给dbo
  • SIMSId 是 GUID 列吗?
  • @Charlieface 是的,SIMSId 是一个 GUID 并引用外部系统。
  • ''(空字符串)不是有效的 GUID。如果你想要 null,就传递 null,如果你想要一个零 GUID,传递那个

标签: python sql-server pandas datetime sqlalchemy


【解决方案1】:

这是我为使其正常工作所做的更改:

  • 将 SIMSId GUID 的空字符串更改为 np.NAN

在进行这些更改后,我收到关于 IDENTITY_ISERT 被关闭的错误消息,因此我必须添加行以将其打开然后再次关闭。如果我不直接插入密钥,则不需要此步骤。

这是我的最终代码:

# Setup dataframe with columns
new_companies = pd.DataFrame(columns=["Id","Name","CreatedDate","ModifiedDate","IsActive","No","SIMSId"])
# Insert two rows
new_companies = new_companies.append({
  "Id":999999,
  "Name":"Unknown",
  "CreatedDate": Timestamp('19010101'),
  "ModifiedDate": Timestamp('19010101'),
  "IsActive":0,
  "No":"999999",
  "SIMSId":np.NAN
}, ignore_index=True)
new_companies = new_companies.append({
  "Id":17,
  "Name":"Acme",
  "CreatedDate": Timestamp('20210228'),
  "ModifiedDate": Timestamp('20210228'),
  "IsActive":0,
  "No":"999999",
  "SIMSId":np.NAN
}, ignore_index=True)

# Connect to database and enable direct insert of ID values
import sqlalchemy
engine = sqlalchemy.create_engine("mssql+pyodbc://*myserver*/*mydatabase?trusted_connection=yes&driver=SQL+Server",echo=False)

command = "SET IDENTITY_INSERT Companies ON"
engine.execute(command)

new_companies.to_sql('Companies',con=engine,if_exists='append',index=False)

command = "SET IDENTITY_INSERT Companies OFF"
engine.execute(command)

【讨论】:

  • 您不应插入身份字段,尤其是用作 PK 时。让 DB 生成值。删除to_sql之前的列。
  • @Parfait 那将是理想的,是的。就我而言,我需要在代码中创建 ID,不能依赖数据库。
猜你喜欢
  • 2020-07-27
  • 2022-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-21
  • 2023-04-03
  • 1970-01-01
相关资源
最近更新 更多