T- SQL Re-usable Error Trapping Code - tsql

I have this error trapping code to write error to a log table. I have to repeat it after ever begin try, end try. I don't want to use a loopback server. I'm using a stored procedure with transaction with rollback if any of the 48 tables have an error on insert or update. It's making my code 2000 lines. Is there a way to make it a class, as there would be in other programming so I don't have to re-paste the same code in my script so many times?
sql server 2008r
insert into powercampustest.dbo.ADDRESSSCHEDULE (
zip_code,
address_line_1,
address_line_2,
address_line_3,
city,
state,
county,
alternate_fax,
email_address,
main_fax,
address_type,
--SEQUENCE_NO,
CREATE_OPID,
CREATE_TERMINAL,
REVISION_OPID,
REVISION_TERMINAL,
PEOPLE_ORG_CODE,
PEOPLE_ORG_ID,
PEOPLE_ORG_CODE_ID,
NO_MAIL,
STATUS,
RECURRING,
APPROVED,
CREATE_DATE,
CREATE_TIME,
REVISION_DATE,
REVISION_TIME)
SELECT
ZIP,
ADDRESS1,
ADDRESS2,
ADDRESS3,
CITY,
STATE,
(SELECT top 1 CC.CODE_VALUE from [powercampustest].[dbo].[CODE_COUNTY] CC, [Bridge_test].[dbo].[PEOPLECHANGES] UC where CC.[LONG_DESC] like '%' + UC.[UCOUNTY] + '%'),
FAX,
UEMAILSCT,
FAX,
--COALESCE(UADDRTYPE, N' '),
'PERM',
--COALESCE(SEQUENCE_NO, 1), --sequence_no, is identity, it should increment
COALESCE(CREATE_OPID, N' '),
COALESCE(CREATE_TERMINAL, N' '),
COALESCE(REVISION_OPID, N' '),
COALESCE(REVISION_TERMINAL, N' '),
COALESCE(PEOPLE_CODE, N' '),
COALESCE(PEOPLE_ID, N' '),
COALESCE(PEOPLE_CODE_ID, N' '),
COALESCE(N' ', N' '),
COALESCE(N' ', N' '),
COALESCE(N' ', N' '),
COALESCE(N' ', N' '),
COALESCE(CREATE_DATE, GetDate()),
COALESCE(CREATE_TIME, GetDate()),
COALESCE(REVISION_DATE, GetDate()),
COALESCE(REVISION_TIME, GetDate())
from Bridge_test.dbo.peoplechanges
WHERE (Processed is Null)
END TRY
BEGIN CATCH
SET #flag = 'true'
INSERT INTO #LogErrorsTable
(
[Error_Number],
[Error_Message],
[Error_Severity],
[Error_State],
[Error_Procedure],
[Error_Line],
[UserName],
[HostName],
[Time_Stamp]
)
SELECT ISNULL(ERROR_NUMBER(),0),
ISNULL(ERROR_MESSAGE(),'NULL Message'),
ISNULL(ERROR_SEVERITY(),0),
ISNULL(ERROR_STATE(),1),
ISNULL(ERROR_PROCEDURE(),''),
ISNULL(ERROR_LINE(), 0),
SUSER_SNAME(),
HOST_NAME(),
GETDATE()
END CATCH

Related

How to insert on different databases tables at the same transaction on a trigger in sql server?

I have a trigger on UPDATE that must insert a row in two tables of different databases, if I comment the second INSERT statement it works if I don't then it does not work at all, how can i solve this?
Here is the code:
BEGIN TRY
BEGIN TRANSACTION
-- MANAGER Table
INSERT INTO DATABASE1.dbo.TABLE (
IDTARJETA, CAJA, FECHA, TIPO, CODIGO, DESCRIPCION, PUNTOS, CONSUMICIONES,
IMPORTE, TICKETS, Z, SERIE, NUMERO, N, ALIAS
)
VALUES
(
#idTarjeta, #caja, #fecha, 1, 0, #descripcion, #puntos, 1,
#saldo_recargado, 1, 0, #serie, #numero, 'B', ' '
);
-- DBFREST Table
INSERT INTO DATABASE2.dbo.TABLE (
IDTARJETA, CAJA, FECHA, TIPO, CODIGO, DESCRIPCION, PUNTOS, CONSUMICIONES,
IMPORTE, TICKETS, Z, SERIE, NUMERO, N, ALIAS
)
SELECT
IDTARJETA, CAJA, FECHA, TIPO, CODIGO,
DESCRIPCION, PUNTOS, CONSUMICIONES,
IMPORTE, TICKETS, Z, SERIE, NUMERO, N, ALIAS
FROM DATABASE1.dbo.TABLE
WHERE NUMERO = #numero
AND SERIE = #serie;
COMMIT
END TRY
BEGIN CATCH
INSERT INTO DATABASE1.dbo.APPS_ERRORS
VALUES
(
SUSER_SNAME(),
ERROR_NUMBER(),
ERROR_STATE(),
ERROR_SEVERITY(),
ERROR_LINE(),
ERROR_PROCEDURE(),
ERROR_MESSAGE(),
GETDATE()
);
ROLLBACK TRANSACTION
END CATCH

Make index use using calculative field T-SQL

We do have one query which is running very frequently but as we are using function on both side of column, it's not doing index seek and this query turn out to be one of the most expensive query. Is there any way i can make this column calculative?
SELECT TOP 1 column1
FROM table1
WHERE replace(replace(replace(column2, char(10), ''), char(13), ''), ' ', '') =
replace(replace(replace(#var1, char(10), ''), char(13), ''), ' ', '')
To expand on dfundako's comment, you can make an index on a persisted calculated column like this:
CREATE TABLE table1 (
column1 INT,
column2 VARCHAR(50),
column3 AS REPLACE(replace(replace(column2, char(10), ''), char(13), ''), ' ', '') PERSISTED
)
CREATE INDEX index1 ON table1 (column3) INCLUDE (column1)
DECLARE #var1 VARCHAR(50)
SELECT column1 FROM dbo.table1 WHERE column3=replace(replace(replace(#var1, char(10), ''), char(13), ''), ' ', '')

Returning empty data from dynamic pivot is there is no data

Code below from how to preserve column names on dynamic pivot is used to create dynamic pivot table.
If source table contains no data, sql error occurs since create table column list end with comma (there are no pivot columns).
How to fix this so that empty table is returned ?
To reproduce, remove insert commands
insert into sales values ( '2016-1-1', 'Ø 12.3/3mm', 2);
insert into sales values ( '2016-1-1', '+-3,4%/3mm', 52);
insert into sales values ( '2016-1-3', '/3,2m-', 246);
from code.
testcase:
create temp table sales ( saledate date, productname char(20), quantity int );
insert into sales values ( '2016-1-1', 'Ø 12.3/3mm', 2);
insert into sales values ( '2016-1-1', '+-3,4%/3mm', 52);
insert into sales values ( '2016-1-3', '/3,2m-', 246);
do $do$
declare
voter_list text;
begin
create temp table myyk on commit drop as
select saledate as kuupaev,
format ('"%s"', replace (upper(productname), ' ', '')) as tootjakood,
sum(quantity)::int as kogus
from sales
group by 1,2
;
drop table if exists pivot;
voter_list := (
select string_agg(distinct tootjakood, ' ' order by tootjakood) from myyk
);
execute(format('
create table pivot (
kuupaev date,
%1$s
)', (replace(voter_list, ' ', ' integer, ') || ' integer')
));
execute (format($f$
insert into pivot
select
kuupaev,
%2$s
from crosstab($ct$
select
kuupaev,tootjakood,kogus
from myyk
order by 1
$ct$,$ct$
select distinct tootjakood
from myyk
order by 1
$ct$
) as (
kuupaev date,
%4$s
);$f$,
replace(voter_list, ' ', ' + '),
replace(voter_list, ' ', ', '),
'',
replace(voter_list, ' ', ' integer, ') || ' integer' -- 4.
));
end; $do$;
select * from pivot;
Postgres 9.1 is used.
Insert an exception handler at the bottom of the DO block body. You can silently ignore errors and create dummy pivot table:
...
exception
when others then
drop table if exists pivot;
create table pivot ("No data" text);
end; $do$;
or raise an exception with your own error message:
...
exception
when others then
drop table if exists pivot;
raise exception 'There is no data in the source dataset.'
end; $do$;
You can also use if-then-else statement:
...
drop table if exists pivot;
if (select count(*) from myyk) > 0 then
voter_list := (
select string_agg(distinct tootjakood, ' ' order by tootjakood) from myyk
);
...
...
else
create table pivot ("No data" text);
end if;
end; $do$;

Rework query to include the Schema in the name

I am leeching off this post: Query to list number of records in each table in a database
With this procedure:
CREATE PROCEDURE ListTableRowCounts
AS
BEGIN
SET NOCOUNT ON
CREATE TABLE #TableCounts
(
TableName VARCHAR(500),
CountOf INT
)
INSERT #TableCounts
EXEC sp_msForEachTable
'SELECT PARSENAME(''?'', 1),
COUNT(*) FROM ? WITH (NOLOCK)'
SELECT TableName , CountOf
FROM #TableCounts
ORDER BY TableName
DROP TABLE #TableCounts
END
GO
The procedure works well enough but I need it to output the name as Schema.Name and sort by that.
Is that possible? I'm not sure how to change this but you can see what it is doing below:
I have several instances were the table names are the same from different schemas.
CREATE PROCEDURE ListTableRowCounts
AS
BEGIN
SET NOCOUNT ON
CREATE TABLE #TableCounts
( SchemaName VARCHAR(500),
TableName VARCHAR(500),
CountOf INT
)
INSERT #TableCounts
EXEC sp_msForEachTable
'SELECT PARSENAME(''?'', 2), PARSENAME(''?'', 1),
COUNT(*) FROM ? WITH (NOLOCK)'
SELECT SchemaName, TableName , CountOf
FROM #TableCounts
ORDER BY TableName, SchemaName
DROP TABLE #TableCounts
END
GO
Taking some code from: https://stackoverflow.com/a/1443723/4584335
and from: How do I list all tables in all databases in SQL Server in a single result set?
Could I suggest this one (just in case "sp_msForEachTable" doesn't exist anymore):
declare #sql nvarchar(max);
select #sql = isnull(#sql + N'union all ', '')
+ N'
select b.name as "DB"
,a.name collate Latin1_General_CI_AI
,a.object_id
,a.schema_id
,' + cast(database_id as nvarchar(10)) + N'
,p.[Rows]
from ' + quotename(name) + N'.sys.tables a
join
' + quotename(name) + N'.sys.indexes i
on a.OBJECT_ID = i.object_id
and i.index_id <= 1
join
' + quotename(name) + N'.sys.partitions p
on i.object_id = p.OBJECT_ID
and i.index_id = p.index_id
join sys.databases b
on database_id=' + cast(database_id as nvarchar(10)) + ' '
from sys.databases
where state = 0
and user_access = 0;
exec sp_executesql #sql;

Dynamic field definitions - can this be done in T-SQL?

I have a requirement that I'm struggling to implement. If possible, I'd like to achieve this with native T-SQL.
I have the following tables:
CUSTOMER
========
ID,
Name
FIELDDEF
========
ID,
Name
FieldType (Char T, N, D for Text, Number or Date)
CUSTOMERFIELD
=============
ID,
CustomerID,
FieldDefID,
CaptureDate,
ValueText,
ValueNumber,
ValueDate
Basically, the purpose of these tables is to provide an extensible custom field system. The idea is that the user creates new field definitions that can be a text, number or date field. Then, they create values for these fields in the ValueText, ValueNumber OR ValueDate field.
Example:
*Customer*
1,BOB
2,JIM
*FieldDef*
1,Mobile,T
1,DateOfBirth,D
*CustomerField*
ID,CustomerID,FieldDefID,CaptureDate,ValueText,ValueNumber,ValueDate
1,1,1,2011-01-1,07123456789,NULL,NULL
2,1,2,2011-01-1,NULL,NULL,09-DEC-1980
3,1,1,2011-01-2,07123498787,NULL,NULL
I need to create a view that looks like this:
*CustomerView*
ID,Name,Mobile,DateOfBirth
1,BOB,07123498787,09-DEC-1980
Note that Bob's mobile is the second one in the list, because it uses the most recent capture date.
Ideally, I need this to be extensible, so if I create a new field def in the future, it is automatically picked up in the CustomerView.
Is this possible in T-SQL at all?
Thanks,
Simon.
This would not be possible with a view, unless the view is dynamically recreated on the fly every time FieldDef changes because view schemas are locked-in at creation time. However, it may be possible with a stored procedure, which may or may not work depending on how you are using it.
Edit 1
Here is a sample query that works just for your current field names, and would have to be modified by dynamic SQL to work in general:
Edit 2
Modified to grab the newest values from the customer field table
with CustomerFieldNewest as (
select
cf1.*
from
customerfield cf1
inner join
(
select
customerid,
fielddefid,
max(capturedate) as maxcapturedate
from
customerfield cf2
group by
customerid,
fielddefid
) cf2 on cf1.customerid = cf2.customerid
and cf1.fielddefid = cf2.fielddefid
and cf1.capturedate = cf2.maxcapturedate
)
,CustomerFieldPivot as (
select
C.ID as ID
,max(case when F.Name = 'Mobile' then CF.ValueText end) as Mobile
,max(case when F.Name = 'DateOfBirth' then CF.ValueDate end) as DateOfBirth
from
Customer C
left join
CustomerFieldNewest CF on C.ID = CF.CustomerID
left join
FieldDef F on F.ID = CF.FieldDefID
group by
C.ID
)
select
C.*
,P.Mobile
,P.DateOfBirth
from
Customer C
left join
CustomerFieldPivot P on C.ID = P.ID
Edit 3
Here is T-SQL code to generate the view on the fly based on the current set of fields in FieldDef (this assumes the view CustomerView already exists, so you will need to create it first as a blank definition or you will get an error). I'm not sure about the performance of all this, but it should work correctly.
declare #sql varchar(max)
declare #fielddef varchar(max)
declare #fieldlist varchar(max)
select
#fielddef = coalesce(#fielddef + ', ' + CHAR(13) + CHAR(10), '') +
' max(case when F.Name = ''' + F.Name + ''' then CF.' +
case F.FieldType
when 'T' then 'ValueText'
when 'N' then 'ValueNumber'
when 'D' then 'ValueDate'
end
+ ' end) as [' + F.Name + ']'
,#fieldlist = coalesce(#fieldlist + ', ' + CHAR(13) + CHAR(10), '') +
' [' + F.Name + ']'
from
FieldDef F
set #sql = '
alter view [CustomerView] as
with CustomerFieldNewest as (
select
cf1.*
from
customerfield cf1
inner join
(
select
customerid,
fielddefid,
max(capturedate) as maxcapturedate
from
customerfield cf2
group by
customerid,
fielddefid
) cf2 on cf1.customerid = cf2.customerid
and cf1.fielddefid = cf2.fielddefid
and cf1.capturedate = cf2.maxcapturedate
)
,CustomerFieldPivot as (
select
C.ID as ID,
' + #fielddef + '
from
Customer C
left join
CustomerFieldNewest CF on C.ID = CF.CustomerID
left join
FieldDef F on F.ID = CF.FieldDefID
group by
C.ID
)
select
C.*,
' + #fieldlist + '
from
Customer C
left join
CustomerFieldPivot P on C.ID = P.ID
'
print #sql
exec(#sql)
select * from CustomerView
You need to build a crosstab which you do with the Pivot statement in TSQL. Here's an article that talks about how to build the pivot dynamically.
http://sqlserver-qa.net/blogs/t-sql/archive/2008/08/27/4809.aspx
Just for completeness there is sql_variant:
declare #t table (typ varchar(1), yuk sql_variant)
insert #t values ('d', getdate())
insert #t values ('i', 1234)
insert #t values ('s', 'bleep bloop')
select
yuk,
case typ
when 'd' then convert(datetime, yuk, 106)+50
when 'i' then cast(yuk as int) * 2
when 's' then reverse(cast(yuk as varchar))
else yuk
end
from #t