Reputation: 1
I am trying to pass a table valued parameter from Python to SQL Server query.
This is my table value that I want pass as a param.
table_values = [
'table_type_name',
'dbo',
(1,None,'Test')
]
Here is my param syntax.
params = [(table_values,None)]
Here I am executing this with pyodbc connection
execute(SAVE_QUERY, params)
Here is my SQL query
SAVE_QUERY= """
SET NOCOUNT ON;
SET ANSI_NULLS ON;
DECLARE @table_values TABLE = ?;
UPDATE
table_name
SET
contacts.is_active = 0,
FROM
table_name
LEFT JOIN
@table_values CC
ON
CC.id = contacts.id
WHERE
CC.email IS NULL;
"""
it is giving me the below error
[42000] [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Incorrect syntax near '='. (102) (SQLExecDirectW); [42000] [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Statement(s) could not be prepared. (8180)
What's the best way to receive the TVP data in this query and store it in variable for using it later part of query.
I have tried removing DECLARE statement but its not working.
Upvotes: 0
Views: 114
Reputation: 123829
As @Charlieface suggests in a comment to the question, for a user-defined table type
CREATE TYPE [dbo].[table_type_name] AS TABLE(
[id] [int] NOT NULL,
[email] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[name] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
the following code would work
table_values = [
"table_type_name",
"dbo",
(1, None, "Test"),
]
save_query = """\
SET NOCOUNT ON;
UPDATE contacts
SET contacts.is_active = 0
FROM contacts LEFT JOIN ? CC ON CC.id = contacts.id
WHERE CC.email IS NULL;
"""
crsr.execute(save_query, (table_values,))
except that the first row of the table data contains a None
value and a known issue with pyodbc raises the error
pyodbc.Error: ('HY004', '[HY004] [Microsoft][ODBC Driver 18 for SQL Server]Invalid SQL data type (0) (SQLBindParameter)')
The workaround is to use OPENJSON() like so:
table_rows_as_tuples = [
(1, None, "Test"),
]
table_rows_as_dicts = [
dict(zip(["id", "email", "name"], tup)) for tup in table_rows_as_tuples
]
save_query = """\
SET NOCOUNT ON;
DECLARE @table_values [dbo].[table_type_name];
INSERT INTO @table_values
SELECT id, email, name
FROM OPENJSON(?)
WITH (
id int,
email nvarchar(255),
name nvarchar(255)
);
UPDATE contacts
SET contacts.is_active = 0
FROM contacts LEFT JOIN @table_values CC ON CC.id = contacts.id
WHERE CC.email IS NULL;
"""
crsr.execute(save_query, (json.dumps(table_rows_as_dicts, default=str),))
Upvotes: 0