我绝对茫然,需要帮助
我可以在SQL Management Studio中运行此查询。
它恰好返回我想要的。导入的BatchID。
但是,一旦我开始在python中运行它,它就会返回错误
“ [ECU服务器的ODBC驱动程序17] [SQL Server] EXECUTE之后的事务计数表明BEGIN和COMMIT语句的数量不匹配。”
或
[在SQL'EXEC [CHAMP_DW]上执行失败。 '#stagingPerformance'。(208)(SQLExecDirectW)“)”
有人在此SQL中看到任何错误吗
示例在bash中有效
sqlcmd -S localhost -U SA -P 'Password' -Q "EXEC [CHAMP_DW].[dbo].[ETL_stage_evestment_performance_to_champ];"
失败的邮件,只有1行被提取
my_conn.execute("EXEC [CHAMP_DW].[dbo].[ETL_stage_evestment_performance_to_champ]")
它是一个非常简单的TRY CATCH,带有一些验证
USE [CHAMP_DW]
GO
/****** Object: StoredProcedure [dbo].[ETL_stage_evestment_performance_to_champ] Script Date: 21/02/2019 4:48:37 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ETL_stage_evestment_performance_to_champ]
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON; --> the only change
/*Variable Declaration*/
DECLARE @BatchImportID UNIQUEIDENTIFIER
DECLARE
@FileProcessedDate DATETIME,
@FileProcessedUTCDate DATETIME,
@ImportStatus TINYINT,
@ErrorCode VARCHAR(2000),
@ErrorMessage VARCHAR(4000),
@StagingID int,
@value_date varchar(255),
@firm_id varchar(255),
@product_id varchar(255),
@vehicle_id varchar(255),
@ccy varchar(255),
@reporting_method varchar(255),
@performance_return varchar(255),
@log_return varchar(255)
/*Assign static value for whole one time process*/
SELECT
@BatchImportID = NEWID(),
@FileProcessedDate = GETDATE(),
@FileProcessedUTCDate = GETUTCDATE()
/*Create staging table so we can re-run procedure instead of having to rerun complete task again and again*/
CREATE TABLE #stagingPerformance
(
[index] [bigint] NULL,
[value_date] [datetime] NULL,
[firm_id] [bigint] NULL,
[ccy] [varchar](max) NULL,
[product_id] [bigint] NULL,
[reporting_method] [varchar](max) NULL,
[vehicle_id] [bigint] NULL,
[performance_return] [float] NULL,
[log_return] [float] NULL
)
CREATE INDEX [IX_EvestmentData_1] ON #stagingPerformance
(
[index] ASC,
[value_date] ASC,
[firm_id] ASC
)
-- POPULATE TEMP TABLE
INSERT INTO #stagingPerformance
SELECT TOP 50 a.[index], a.value_date, a.firm_id, a.ccy,
a.product_id, a.reporting_method, a.vehicle_id, a.performance_return, a.log_return
FROM CHAMP_DW.dbo.champ_dw_staging_evestment_performance a
--WHERE a.reporting_method<>'Index'
/*While loop started to get process record one by one*/
WHILE EXISTS(SELECT 1 FROM #stagingPerformance AS FHD WITH (NOLOCK))
BEGIN
BEGIN TRY
BEGIN TRANSACTION
/*To assign 1 record values to respective variables*/
SELECT TOP 1
@StagingID = FHD.[index],
@firm_id = NULLIF(FHD.[firm_id],''),
@product_id = NULLIF(FHD.[product_id],''),
@vehicle_id = NULLIF(FHD.[vehicle_id],''),
@value_date = NULLIF(FHD.[value_date],''),
@reporting_method = NULLIF(FHD.[reporting_method],''),
@ccy = NULLIF(FHD.[ccy],''),
@performance_return = NULLIF(FHD.[performance_return],''),
@log_return = NULLIF(FHD.[log_return],'')
FROM #stagingPerformance AS FHD WITH (NOLOCK)
--WHERE reporting_method <> 'Index'
ORDER BY FHD.[index]
/*Record wise validation start*/
IF @firm_id IS NULL BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + ',' + '101',
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Firm ID is required.'
END
IF @product_id IS NULL BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + ',' + '102',
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Product ID is required.'
END
IF @value_date IS NULL BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + ',' + '103',
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Value Date is required.'
END
IF @reporting_method IS NULL BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + ',' + '104',
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Reporting Method is required.'
END
IF @reporting_method IS NOT NULL AND NOT EXISTS(SELECT 1 WHERE @reporting_method in ('Gross', 'Net', 'Index')) BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + ',' + '115',
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Reporting Method is invalid'
END
IF @ccy IS NULL BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + ',' + '105',
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'ccy is required.'
END
IF @value_date IS NOT NULL AND ISDATE(@value_date) = 0 BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + ',' + '106',
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Invalid value of Value Date.'
END
IF @performance_return IS NOT NULL AND ISNUMERIC(@performance_return) = 0 BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + CASE WHEN @ErrorCode LIKE '%112%' THEN '' ELSE ',' + '112' END,
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Invalid value of performance.'
END
IF @log_return IS NOT NULL AND ISNUMERIC(@log_return) = 0 BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + CASE WHEN @ErrorCode LIKE '%112%' THEN '' ELSE ',' + '112' END,
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Invalid value of log_return.'
END
IF @firm_id IS NOT NULL AND NOT EXISTS(SELECT 1 FROM CHAMP_DW.dbo.champ_dw_fund_manager_mapping AS DFM WITH (NOLOCK) WHERE DFM.evestment_fund_manager_id = @firm_id)
BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + ',' + '113',
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Firm ID is not Mapped'
END
IF @product_id IS NOT NULL AND NOT EXISTS(SELECT 1 FROM dbo.champ_dw_product_mapping AS DAM WITH (NOLOCK) WHERE DAM.evestment_product_id =@product_id)
BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + ',' + '114',
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Product ID is not Mapped'
END
IF @ccy IS NOT NULL AND NOT EXISTS(SELECT 1 FROM [dbo].champ_dw_dim_currency AS DC WITH (NOLOCK) WHERE DC.currency = @ccy) BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + ',' + '112',
@ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'ccy is not found in DIM_ccy.'
END
SELECT
@ErrorCode = NULLIF(STUFF(@ErrorCode,1,1,''),''),
@ErrorMessage = NULLIF(STUFF(@ErrorMessage,1,1,''),'')
IF @ErrorMessage IS NOT NULL
BEGIN
;THROW 50552,'VALIDATION RAISE ERROR.',1
END
/*Record wise validation end*/
/*To get unique record value based on FundID, AssetID, AsAtDate columns*/
DECLARE
@performance_id INT = 0,
@vfirm_id INT,
@vproduct_id INT,
@vvehicle_id INT,
@vvalue_date datetime2,
@vreporting_method nvarchar(max),
@vccy nvarchar(3),
@vperformance_return float,
@vlog_return float,
@map_firm_id INT,
@map_product_id INT
SELECT
@vfirm_id = TRY_PARSE(@firm_id AS INT),
@vproduct_id = TRY_PARSE(@product_id AS INT),
@vvehicle_id = TRY_PARSE(@vehicle_id AS INT),
@vvalue_date = TRY_PARSE(@value_date AS datetime2),
@vreporting_method = @reporting_method,
@vccy = cast(@ccy as nvarchar(3)),
@vperformance_return = TRY_PARSE(@performance_return AS float),
@vlog_return = TRY_PARSE(@log_return AS float)
SELECT @map_firm_id = (SELECT fund_manager_mapping_id FROM CHAMP_DW.dbo.champ_dw_fund_manager_mapping fm WHERE fm.evestment_fund_manager_id = @vfirm_id)
SELECT @map_product_id = (SELECT product_mapping_id FROM CHAMP_DW.dbo.champ_dw_product_mapping fp WHERE fp.product_mapping_id=@vvehicle_id)
-- changing to vehicle mapping
--SELECT @map_product_id = (SELECT product_mapping_id FROM CHAMP_DW.dbo.champ_dw_product_mapping fp WHERE fp.evestment_vehicle_id=@vvehicle_id)
SELECT
@performance_id = FFHD.performance_id
FROM dbo.[champ_dw_fact_performance] AS FFHD WITH (NOLOCK)
WHERE FFHD.fund_manager_id = @map_firm_id
AND FFHD.product_id = @map_product_id
AND FFHD.value_date = @vvalue_date
AND FFHD.data_source = 'eVestment'
AND FFHD.ccy_id = @vccy
AND FFHD.reporting_method = @vreporting_method
/*Update record, if any value has different then already exist in DB.*/
UPDATE FFHD
SET
FFHD.ccy_id = @ccy,
FFHD.performance_return = @vperformance_return,
FFHD.log_return = @vlog_return
FROM dbo.[champ_dw_fact_performance] AS FFHD WITH (NOLOCK)
WHERE FFHD.performance_id = @performance_id
AND
(
ISNULL(FFHD.performance_return,'0') <> @vperformance_return
OR
ISNULL(FFHD.log_return,'0') <> @vlog_return
)
/*Add new record if record is not found based on FundID, AssetID, AsAtDate columns*/
INSERT INTO dbo.[champ_dw_fact_performance]
(
value_date,
reporting_method,
valuation_quality,
data_source,
performance_return,
log_return,
ccy_id,
fund_manager_id,
product_id
)
SELECT
@vvalue_date AS value_date,
@vreporting_method AS reporting_method,
'Actual' as valuation_quality,
'eVestment' as data_source,
@vperformance_return AS performance_return,
@vlog_return AS log_return,
@vccy AS ccy_id,
@map_firm_id AS fund_manager_id_id,
@map_product_id AS product_id_id
WHERE NOT EXISTS
(
SELECT
1
FROM dbo.[champ_dw_fact_performance] AS FFHD WITH (NOLOCK)
WHERE FFHD.fund_manager_id = @map_firm_id
AND FFHD.product_id = @map_product_id
AND FFHD.value_date = @vvalue_date
AND FFHD.data_source = 'eVestment'
AND FFHD.ccy_id = @vccy
AND FFHD.reporting_method = @vreporting_method
)
--/*To add success record in log table*/
INSERT INTO dbo.[champ_dw_fact_performance_log]
( BatchImportID,
FileProcessedDate,
FileProcessedUTCDate,
ImportStatus,
ErrorCode,
ErrorMessage,
StagingID,
value_date,
reporting_method,
valuation_quality,
data_source,
ccy_id,
performance_return,
log_return,
firm_id,
product_id,
vehicle_id
)
SELECT
@BatchImportID AS BatchImportID,
@FileProcessedDate AS FileProcessedDate,
@FileProcessedUTCDate AS FileProcessedUTCDate,
1 AS ImportStatus,
'100' AS ErrorCode,
'Success' AS ErrorMessage,
@StagingID AS StagingID,
@value_date AS value_date,
@reporting_method AS reporting_method,
'Actual' AS valuation_quality,
'eVestment' AS data_source,
@ccy AS ccy_id,
@performance_return AS performance_return,
@log_return AS log_return,
@firm_id AS firm_id,
@product_id AS product_id,
@vehicle_id AS vehicle_id
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK
--BEGIN
-- ROLLBACK TRANSACTION
--END
DECLARE
@ERROR_MESSAGE NVARCHAR(4000)
SELECT
@ERROR_MESSAGE = ERROR_MESSAGE()
IF @ERROR_MESSAGE <> 'VALIDATION RAISE ERROR.'
BEGIN
SELECT
@ErrorCode = ISNULL(@ErrorCode,'') + CASE WHEN ISNULL(@ERROR_MESSAGE,'') <> '' THEN ',' + '999' ELSE '' END,
@ErrorMessage = ISNULL(@ErrorMessage,'') + CASE WHEN ISNULL(@ERROR_MESSAGE,'') <> '' THEN ',' + CONVERT(VARCHAR(4000),@ERROR_MESSAGE) ELSE '' END
END
SELECT
@ErrorCode = NULLIF(CASE WHEN @ErrorCode LIKE '%999%' THEN STUFF(@ErrorCode,1,1,'') ELSE @ErrorCode END,''),
@ErrorMessage = NULLIF(CASE WHEN @ErrorCode LIKE '%999%' THEN STUFF(@ErrorMessage,1,1,'') ELSE @ErrorMessage END,'')
/*To add failed record in log table*/
INSERT INTO dbo.[champ_dw_fact_performance_log]
(
BatchImportID,
FileProcessedDate,
FileProcessedUTCDate,
ImportStatus,
ErrorCode,
ErrorMessage,
StagingID,
value_date,
reporting_method,
valuation_quality,
data_source,
ccy_id,
performance_return,
log_return,
firm_id,
product_id,
vehicle_id
)
SELECT
@BatchImportID AS BatchImportID,
@FileProcessedDate AS FileProcessedDate,
@FileProcessedUTCDate AS FileProcessedUTCDate,
0 AS ImportStatus,
@ErrorCode AS ErrorCode,
@ErrorMessage AS ErrorMessage,
@StagingID AS StagingID,
@value_date AS value_date,
@reporting_method AS reporting_method,
'Actual' AS valuation_quality,
'eVestment' AS data_source,
@ccy AS ccy_id,
@performance_return AS performance_return,
@log_return AS log_return,
@firm_id AS firm_id,
@product_id AS product_id,
@vehicle_id AS vehicle_id
END CATCH
DELETE FHD
FROM #stagingPerformance AS FHD
WHERE FHD.[index] = @StagingID
SELECT
@firm_id = NULL,
@product_id = NULL,
@vehicle_id = NULL,
@value_date = NULL,
@reporting_method = NULL,
@ccy = NULL,
@performance_return = NULL,
@log_return = NULL,
@ImportStatus = NULL,
@ErrorCode = NULL,
@ErrorMessage = NULL
END
SELECT @BatchImportID as 'BatchID'
DROP TABLE #stagingPerformance
END
答案 0 :(得分:0)
每当有外部BEGIN TRAN时,我总是会遇到这种类型的问题。意味着存储过程的调用者也具有BEGIN TRAN。因为当您进行回滚时,外部呼叫者还需要检查是否还有一个开放的连接要提交。因此,外部调用者之前的回滚或提交必须检查是否仍然存在打开的连接。
根据我的经验,您只能回滚一次。并且@@ TRANCOUNT设置为零。
证明:
1)有效-多次提交
BEGIN TRAN
BEGIN TRAN
COMMIT TRAN
COMMIT TRAN
2)不起作用-在中间回滚
BEGIN TRAN
BEGIN TRAN
ROLLBACK TRAN
COMMIT TRAN
3)最后正确提交-检查事务是否仍然存在。
BEGIN TRAN
BEGIN TRAN
ROLLBACK TRAN
IF (@@TRANCOUNT>0)
COMMIT TRAN
至少,我建议您所有的提交和回滚检查@@ TRANCOUNT> 0。