2013-08-05 2 views
5

Я пытаюсь использовать zxJDBC для подключения к базе данных, работающей на SQL Server 2008 R2 (Express), и вызвать хранимую процедуру, передав ей один параметр. Я использую jython-standalone 2.5.3 и в идеале не хочу устанавливать дополнительные модули.Какое правильное использование zxjdbc для вызова хранимых процедур?

Мой тестовый код показан ниже.

имя базы данных CSM

хранимых процедур:

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
-- ============================================= 
-- Author:  <Author,,Name> 
-- Create date: <Create Date,,> 
-- Description: <Description,,> 
-- ============================================= 
CREATE PROCEDURE dbo.DUMMY 
    -- Add the parameters for the stored procedure here 
    @carrierId VARCHAR(50) 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    -- Insert statements for procedure here 
    INSERT INTO dbo.carrier (carrierId, test) 
    VALUES (@carrierId, 'Success') 
END 
GO 

Jython Сценарий:

from com.ziclix.python.sql import zxJDBC 

conn = None 
try : 
    conn = zxJDBC.connect('jdbc:sqlserver://localhost\SQLEXPRESS', 'sa', 'password', 'com.microsoft.sqlserver.jdbc.SQLServerDriver') 
    cur = conn.cursor() 
    cur.callproc(('CSM','dbo','DUMMY'), ['carrier1']) 
    conn.commit() 
except Exception, err : 
    print err 
    if conn: 
     conn.rollback() 
finally : 
    if conn : 
     conn.close() 

С помощью cur.execute() я смог убедиться, что выше успешного подключения к базы данных, и я могу запросить его. Однако до сих пор мне не удалось успешно вызвать хранимую процедуру с параметрами.

Документация here (возможно, устаревшая?) Указывает, что callproc() может быть вызвана либо строкой, либо кортежем для идентификации процедуры. Данный пример -

c.callproc(("northwind", "dbo", "SalesByCategory"), ["Seafood", "1998"], maxrows=2) 

При попытке использовать этот метод, я получаю следующую ошибку

Error("Could not find stored procedure 'CSM.DUMMY'. [SQLCode: 2812], [SQLState: S00062]",) 

Казалось бы, что zxJDBC пренебрегает включить dbo часть идентификатора процедуры.

Если я вместо этого позвонить callproc с «CSM.dbo.DUMMY» в качестве первого аргумента, то я получаю эту ошибку

Error('An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name. [SQLCode: 1038], [SQLState: S0004]',) 

с использованием профилировщика в базе данных в то время как работает мой сценарий показывает, что во втором случае следующий SQL выполняется:

use [] 
go 

Так что, казалось бы, что при использовании одной строки, чтобы определить процедуру, имя базы данных не правильно разобран вне.

Один из моих проб и ошибок попытки исправить это назвать callproc следующим образом:

cur.callproc(('CSM', '', 'dbo.DUMMY'), ['carrier1']) 

Это заставило меня настолько, насколько

Error("Procedure or function 'DUMMY' expects parameter '@carrierId', which was not supplied. [SQLCode: 201], [SQLState: S0004]",) 

В этом случае то, что я думаю происходит то, что zxJDBC пытается вызвать системную хранимую процедуру (sp_proc_columns), чтобы определить требуемые параметры для хранимой процедуры, которую я хочу вызвать. Я предполагаю, что с идентификатором процедуры в неправильном формате выше, zxJDBC не получает действительный/правильный возврат и не предполагает, что параметры не требуются.

Поэтому в основном я не немного застряли для идей о том, как получить его

  • Используйте правильное имя базы данных
  • правильно определить требуемые параметры с помощью sp_proc_columns
  • Call My хранимой процедуры правильное название

все в то же время.

У меня есть обходной путь, который должен использовать что-то вроде

cur.execute('EXEC CSM.dbo.DUMMY ?', ['carrier1']) 

Однако я чувствую, что callproc() является правильным решением, и, скорее всего, производить чистый код, когда я пришел, чтобы вызывать хранимые процедуры с большим количеством параметры.

Если кто-нибудь может определить ошибки, которые я делаю, или знает, что это никогда не будет работать, как я думаю, тогда любой вклад был бы высоко оценен.

Благодаря

Редактировать

Как предложенное я-один, я попытался добавить cur.execute('USE CSM') перед вызовом моей хранимой процедуры (также удаление имени базы данных из процедуры вызова). Это, к сожалению, приводит к тому, что ошибка объекта или столбца отсутствует, как указано выше. Профайлер показывает USE CSM, а затем USE [], поэтому кажется, что callproc() всегда запускает инструкцию USE перед самой процедурой.

Я также экспериментировал с включением/выключением autocommit, но безрезультатно.

Edit 2

Дополнительная информация Следующие комментарии/Предлагаемые решения:

  • "SQLEXPRESS" в моей строке соединения это имя экземпляра базы данных.
  • Использование двойных кавычек вместо одиночного не влияет.
  • Включая имя базы данных в строку подключения (через ;databaseName=CSM;, как указано here), и опускает ее из вызова callproc(), приводит к исходной ошибке с запущенным оператором USE [].

Использование callproc(('CSM', 'dbo', 'dbo.DUMMY'), ['carrier1']) дает мне некоторый прогресс, но приводит к ошибке

Error ("Процедура или функция„пустышки“ожидает параметр„@carrierId“, который не поставлялся.[SQLCODE: 201], [SQLState: S0004]»,)

Я попытаюсь исследовать это еще больше

Редактировать 3

Основываясь на запросах я мог видеть zxJDBC стрельбы, я вручную выполнены следующие против моей базе данных:.

use CSM 
go 
exec sp_sproc_columns_100 N'dbo.DUMMY',N'dbo',N'CSM',NULL,N'3' 
go 

Это дало мне пустой набор результатов, которые, казалось бы объяснить, почему zxJDBC не проходит никаких параметров хранимой процедуры - это не думаю, что это нужно мне еще чтобы понять, почему это происходит.

Edit 4

Для обновления выше, пустой набор результатов, потому что вызов должен быть

exec sp_sproc_columns_100 N'DUMMY',N'dbo',N'CSM',NULL,N'3' 

К сожалению, это приносит мне полный круг, как я не могу удалить dbo владельца от имя хранимой процедуры в вызове callproc() или процедура не будут найдены вообще.

Редактировать определение 5

Таблицы по запросу

CREATE TABLE [dbo].[carrier](
    [carrierId] [varchar](50) NOT NULL, 
    [test] [varchar](50) NULL 
) ON [PRIMARY] 
+0

На самом деле я не испытал, чтобы ответить, я просто вижу, что время баунти выходит, и вы наедине с вашей проблемой. Одна вещь, которую я заметил в документах zxjdbc. Не могли бы вы попытаться следовать? После запуска курсора (после 'cur = conn.cursor()') попробуйте 'c.execute (« использовать CSM »)' (это должно переключить контекст из базы данных 'master' в' CSM' и разрешить ссылку на объекты db без имени db prefix), а затем попробуйте 'cur.callproc (" dbo.DUMMY ", [" carrier1 "])' или даже 'cur.callproc (" DUMMY ", [" carrier1 "])'. Что произойдет, если вы это сделаете? –

+0

@ i-one Спасибо за предложение. Мне не повезло с этим, я боюсь, но отредактировал вопрос с описанием результата – Vindicare

+0

Может быть 'cur.callproc (('CSM', '', 'dbo.DUMMY?'), [' operator1 ']) 'или' cur.callproc ((' CSM ',' ',' dbo.DUMMY @carrierId '), [' carrier1 ']) '? –

ответ

2

Хотя совершенно не знает о технологиях, используемых здесь (если некоторые незначительные знания SQL Server), я попытаюсь ответить (пожалуйста, простите меня если мой синтаксис jython неверен. Я пытаюсь описать возможности здесь не точного кода)

Мой первый подход (найдено по адресу this post) - это попробовать:

cur.execute("use CSM") 
cur.callproc(("CSM","dbo","dbo.DUMMY"), ["carrier1"]) 

Это должно быть связано с тем, что sa пользователи всегда имеют dbo как схемы по умолчанию (как описано в this SO post)

Если выше не работает, я бы также попытаться использовать базу данных CSM имя в URL-адресе JDBC (это очень часто встречается при использовании JDBC для других баз данных), а затем просто вызывайте один из двух ниже.

cur.callproc("DUMMY", ["carrier1"]) 
cur.callproc("dbo.DUMMY", ["carrier1"]) 

Я надеюсь, что это помогает

Update: цитирует соответствующую часть ссылки, которую вы не можете просматривать

>> Program calls a Stored Procedure - master.dbo.xp_fixeddrives on MS SQL Server 

from com.ziclix.python.sql import zxJDBC 

def getConnection(): 
    url = "${DBServer.Url}" 
    user= "${DBServer.User}" 
    password = "${DBServer.Password}" 
    driver = "${DBServer.Driver}" 
    con = zxJDBC.connect(url, user, password, driver) 
    return con 

try: 
    conn = getConnection() 
    print 'Connection successful' 
    cur = conn.cursor() 
    cur.execute("use master") 
    cur.callproc(("master", "dbo", "dbo.xp_fixeddrives")) 
    print cur.description 
    for a in cur.fetchall(): 
     print a 
finally: 
    cur.close() 
    conn.close() 
    print 'Connection closed' 

ошибки вы получаете, когда вы определили функцию вызова как и выше, указывает, что параметр не передан правильно. Поэтому, пожалуйста, измените хранимую процедуру, чтобы принять значение по умолчанию и попытайтесь позвонить с передачей params = [None]. Если вы видите, что вызов преуспевает, мы должны сделать что-то в этом отношении, насколько это необходимо для указания базы данных. Btw: most recent documentation предлагает вам иметь доступ к нему с вашим синтаксисом.

+0

Я обновил вопрос с помощью результатов этих предложений. Первый подход дал мне некоторый прогресс, но, к сожалению, я не могу просмотреть связанную ссылку из-за фильтров на работе. – Vindicare

+0

@ Vindicare см. Мое обновление. –

+0

Если вы видите мои правки 3 и 4 выше, я уверен, что проблема с «dbo» стороной вещей. Подключение к базе данных в порядке, но при использовании кортежа для указания имени хранимой процедуры средний элемент (dbo), кажется, игнорируется. Добавление этого к последнему элементу будет работать только в ситуации, когда хранимая процедура не имеет параметров, поскольку имя dbo.procName не является правильным именем процедуры, поэтому требуемые параметры не определяются sp_sproc_columns – Vindicare

2

Как указано в комментариях callproc будет работать только с SELECT.Вместо этого попробуйте этот подход:

cur.execute("exec CSM.dbo.DUMMY @Param1='" + str(Param1) + "', @carrierId=" + str(carrierID)) 

Для получения более подробной информации см. this link.

+0

Я наткнулся на эту ссылку, которая является частью того, что привело меня к обходному пути, упомянутому в моем вопросе. Однако в нем ничего не говорится о проблеме SELECT vs INSERT, и я считаю, что мое расследование показывает, что это не проблема. Кроме того, в документации [здесь] (http://www.jython.org/jythonbook/en/1.0/DatabasesAndJython.html#prepared-statements) рекомендуется не использовать конкатенацию строк для построения запросов, но подготовленные заявления (в соответствии с моим примером) – Vindicare

Смежные вопросы