Warning on altering columns in Sybase - sql

I am running the following sql code in sybase
Declare #cp int
select #cp = count(*) from syscolumns where id = object_id('activ') and name = 'pending'
if (#cp = 0 )
begin
execute("
ALTER TABLE activ ADD pending char(1) DEFAULT 'Y'
")
print 'pending added '
end
When I run for the first time I get a "warning: The schema for table activ has changed. Drop and re-create each trigger on this table that uses the if update clause"
On subsequent runs I don't get this warning anymore. Is there any way to avoid getting this warning first time ?
Some helpful links I went through. 1 Information about the error itself. I still have no clue how to remove that error/warning.

Related

SQL Code Evaluation stopping a valid transaction

As part of the company I am working for at the moment I need to create some database upgrade scripts to replace some work of a previous contractor.
The code before the following block runs, creates the new ID column, and then this script looks to populate the values and then drop some columns.
IF EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[Central].[Core.Report].[ReportLessonComp]')
AND name = 'Name')
and
EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[Central].[Core.Report].[ReportLessonComp]')
AND name = 'Code')
BEGIN
UPDATE
[Central].[Core.Report].[ReportLessonComp]
SET
CompetencyId = rc.Id
FROM
[Central].[Core.Report].[ReportLessonComp] rlc
INNER JOIN
[Core.Lookup].ReportCompetency rc
ON
rc.Code = rlc.Code and rc.Name = rlc.Name
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN CODE
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN [Name]
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN [Description]
END
GO
When running the if exists \ not exists checks and then select getdate() this works perfeclty fine and gives me the result I expect.
However, when I run the code block above I get error
Msg 207, Level 16, State 1, Line 23
Invalid column name 'Code'.
Msg 207, Level 16, State 1, Line 23
Invalid column name 'Name'.
This script it part of a larger upgrade script and is used in a system calle RoundHouse https://github.com/chucknorris/roundhouse which is the system chosen by the company.
Prior to the above if exists check,
IF (SELECT COUNT(1) FROM sys.columns
WHERE OBJECT_ID = OBJECT_ID('[Central].[Core.Report].[ReportLessonComp]')
AND Name in ('Name','Code')) = 2
which also gave the same issue. I have five tables that I need to update and this is going to stop the team from working if I cant resolve this at my next PR
What can I do in order to stop this from causing the upgrade scripts to fail?
EDIT -- The reason I am linking on varchar fields also is because the previous developer did not create relationships between tables, and was just inserting strings into tables rather than relating by ID causing the potential for unlinked \ inconsistent data.
The table edit prior to this creates the new id column, and this script is getting the value and dropping columns that are no longer needed
SQL Server will parse the whole of the statement prior to execution, so the exists check does not protect you from the update being parsed. If the column has already been dropped, that makes the statement invalid and you get a parse error. The update statement would have to be executed as dynamic SQL, sp_execute basically so that the varchar of the update is not directly parsed.
For SQL Server 2016 and above the drop column can be protected a bit more as well:
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN IF EXISTS CODE

A rowset based on the SQL command was not returned by the OLE DB provider

I was wondering if anyone can help me with this issue? I am calling a sproc in SSIS. All I want it to do is create a file if any new records are updated or inserted into a table. That table checks another source table to see if anything changed in that table and then adds it to the copy table, if there are any updates or changes to the source table I want a file to get created and if not we don't want it to do anything.
I have tested the logic and everything seems to work fine but once I try to run the sproc in SSIS it gives the error message, "A rowset based on the SQL command was not returned by the OLE DB provider." Initially I thought this means that it is erroring out because no rows are being returned but even when there are rows being returned I still get the very same error message. I can parse the query and preview the results in SSIS but it still turns red when run and gives that error message.
Below is the code to my sproc. Any help or ideas would be so appreciated!
USE [dev02]
GO
/****** Object: StoredProcedure [dbo].[usp_VoidReasons] Script Date: 8/25/2016 11:54:44 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*-------------------------------------------------------------------------- ----
Author: Andrej Friedman
Create date: 07/27/2016
Description: This sproc assists SSIS in creating a file but only when a new row has been added to the VoidReasonsLookup table
that didnt exist there before or if the code or description has changed in that table. The table is compared to the prod1.dbo.miscde
table for diferences and only for the Void Reasons of that table (mcmspf = 'cv').
History:
SampleCall: EXEC [dbo].[usp_VoidReasons]
--truncate table dev02.dbo.VoidReasonsLookup
--select * from dbo.VoidReasonsLookup
--update VoidReasonsLookup set Description = 'BB' where Description = 'BENEFIT CODE ADJUSTMENT'
------------------------------------------------------------------------------*/
ALTER proc [dbo].[usp_VoidReasons]
as
declare #ImportDate as date = CONVERT (date, GETDATE())
insert into VoidReasonsLookup (Code, [Description])
--Change #1 -- New Code and Description
--This will insert a new row in the VoidReasons table where the Code and description doesnt exist there but exists in the source table.
select (M.mcmscd_1 + M.mcmscd_4) as Code, mcmsds as [Description] from prod1.dbo.miscde M
left join VoidReasonsLookup VL
on M.mcmscd_1 + M.mcmscd_4 = VL.Code
where M.mcmspf = 'cv'
and VL.Code is null
--Change #2 -- Code dropped off source table so we need it gone from the VoidReasons table
--This will delete rows where the Code doesnt exists in the source table any longer
delete from VL from VoidReasonsLookup as VL
left join prod1.dbo.miscde as M
on VL.Code = M.mcmscd_1 + M.mcmscd_4
where M.mcmscd_1 + M.mcmscd_4 is null
--Change #3 -- Description has changed for a certain code in the source table.
--This will update the Description to the source table if it is different in the VoidReasons table and update the ImportDate to today when that update took place.
update VL
set VL.[Description] = M.mcmsds,
VL.ImportDate = #ImportDate
from dbo.VoidReasonsLookup as VL
join prod1.dbo.miscde as M
on VL.Code = M.mcmscd_1 + M.mcmscd_4
where VL.[Description] <> M.mcmsds
and M.mcmspf = 'cv'
--This will give back everything in the VoidReasons table but only if todays date is the same as the ImportDate column of the table.
--This will mean that today a record was inserted or updated.
If exists(select ImportDate from VoidReasonsLookup
where ImportDate = #ImportDate)
select * from VoidReasonsLookup
else
print 'no changes detected in VoidReasons table'
Add SET NOCOUNT ON and at the end you are selecting resultset basedon condition, SSIS expects resultset always based on output type which you configured. You can use empty resultset as an output will solve the problem
Comment out everything, rerun and see if you still get the error. Uncomment parts until you get the error. Once you get the error, you know what is causing the issue.

SQL Server : update value if it does not exist in a column

I am using SQL Server 2008 and trying to create a statement which will update a single value within a row from another table if a certain parameter is met. I need to make this as simple as possible for a member of my team to use.
So in this case I want to store 2 values, the Sales Order and the reference. Unfortunately the Sales order has a unique identifier that I need to record and enter into the jobs table and NOT the actual sales order reference.
The parameter which needs to be met is that the Sales order unique identifier cannot exist anywhere in the sales order column within the jobs table. I can get this to work when the while value is set to 1 but not when it's set to 0 and in my head it should be set to 0. Anyone got any ideas why this doesn't work?
/****** Attach an SO to a WO ******/
/****** ONLY EDIT THE VALUES BETWEEN '' ******/
Declare #Reference nvarchar(30);
Set #Reference = 'WO16119';
Declare #SO nvarchar(30);
Set #SO = '0000016205';
/****** DO NOT ALTER THE CODE BEYOND THIS POINT!!!!!!!!!!!!! ******/
/* store more values */
Declare #SOID nvarchar(30);
Set #SOID = (Select SOPOrderReturnID
FROM Test_DB.dbo.SOTable
Where DocumentNo = #SO);
/* check if update should run */
Declare #Check nvarchar (30);
Set #Check = (Select case when exists (select *
from Test_DB.dbo.Jobs
where SalesOrderNumber != #SOID)
then CAST(1 AS BIT)
ELSE CAST(0 AS BIT) End)
While (#Check = 0)
/* if check is true run code below */
Begin
Update Test_DB.dbo.jobs
SET SalesOrderNumber = (Select SOPOrderReturnID
FROM Test_DB.dbo.SOPOrderReturn
Where DocumentNo = #SO)
Where Reference = #Reference
END;
A few comments. First in order to avoid getting into a never ending loop you may want to change your while for an IF statement. You aren't changing the #check value so that will run forever:
IF (#Check = 0)
BEGIN
/* if check is true run code below */
Update Test_DB.dbo.jobs
SET SalesOrderNumber = (Select SOPOrderReturnID
FROM Test_DB.dbo.SOPOrderReturn
Where DocumentNo = #SO)
Where Reference = #Reference
END
Then, without knowing your application I would say that the way you make checks is going to require you to lock your tables to avoid other users invalidating the results of your SELECTs.
I would go instead to creating a UNIQUE constraint over the column you want to be unique and handle the error gracefully. This way you don't need to create big locks on your tables
CREATE UNIQUE INDEX IX_UniqueIndex ON Test_DB.dbo.Jobs(SalesOrderNumber)
As per your comment if you cannot create a unique index you may want to try the following SQL although it could cause too much locking and be affected by race conditions:
IF NOT EXISTS (SELECT 1 FROM Test_DB.dbo.Jobs j INNER JOIN Test_DB.dbo.SOTable so ON j.SalesOrderNumber = so.SPOrderReturnId)
BEGIN
UPDATE Test_DB.dbo.jobs
SET SalesOrderNumber = so.SOPOrderReturnID
FROM
Test_DB.dbo.Jobs j
INNER JOIN Test_DB.dbo.SOTable so ON j.SalesOrderNumber = so.SPOrderReturnId
Where
Reference = #Reference
END
The risk of this are that you are running to separate queries (the select and the update) so between them the state of the database could change. So it may be possible that the first query returns nothing exists for that Id but at the moment of the update other user has inserted/updated that data so the previous result is no longer true.
You can try to avoid this problem by using a isolation level that locks the table on the read (like Serializable) but that could cause locks and even deadlocks in the database.
The best solution here is the unique index. If a certain column has to be unique inside a table the best controller system is the db itself by defining constraints.

IF EXISTS command appears to be executing, even when condition doesn't exist?

I have the following SQL statement within a large update script:
...
PRINT N'Updating Table_01, Applying TypeReassignment from YesNoField_01 data'
IF EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'[dbo].[Table_01]')
AND name = 'YesNoField_01')
BEGIN
UPDATE Table_01 SET TypeReassignment = CASE YesNoField_01 WHEN 'Y' THEN 2 ELSE 1 END
WHERE TypeReassignment = 0
END
...
//script continues with other modifications. Towards the end of my script
//the YesNoField_01 field is dropped from the table.
The intent of the IF statement is to execute an UPDATE on a specific column only if another field exists on the table. As my comment at the end suggests, I am removing this original column (YesNoField_01) towards the end of my script.
The purpose of the IF check is so the script can be executed multiple times, even if it has been executed once before. If part of this script has been executed, it needs to skip over completed steps and continue execution without any errors. In this case, I need to skip over a data update.
However, if I execute my script on a database that has already had this script executed once before, I am getting the following error.
Invalid column name 'YesNoField_01'
When I navigate to the failing statement, it appears that the script is attempting to execute the UPDATE command within the IF block. When you independently execute the SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'[dbo].[Table_01]') AND name = 'YesNoField_01' statement, you see that nothing is returned because the field YesNoField_01 has already been removed from the table.
I'm confused. If my SELECT statement does not result in an existing record, why am I getting an execution error from within the IF block? Or, a better question, why is it even trying to execute my IF block when the IF conditional should evaluate to false?
Perhaps you could alter the test to check for the column's existence indirectly, thus:
DECLARE #YN_FieldName sysname =
(
SELECT Name
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[dbo].[Table_01]')
AND name = 'YesNoField_01'
)
IF #YN_FieldName IS NOT NULL
BEGIN
UPDATE
Table_01
SET TypeReassignment =
CASE YesNoField_01
WHEN 'Y' THEN 2
ELSE 1
END
WHERE
TypeReassignment = 0
END
I suspect, though, that dynamic SQL will be required.

MS SQL IF Statement Executing IF and ELSE Blocks

All, I have the following query
IF NOT EXISTS (SELECT name
FROM sys.databases
WHERE name = N'Report')
BEGIN
DECLARE #DatabasePath NVARCHAR(1000);
SET #DatabasePath = (SELECT ResultMessage + '\'
FROM [Admin]..[Process]);
EXEC ispCREATEDB N'Report', #DatabasePath, N'10MB', N'20%'
END
ELSE
BEGIN
IF EXISTS (SELECT *
FROM Report.sys.objects
WHERE name = N'FatalErrSumm' AND type = N'U')
BEGIN
DROP TABLE [Report]..[FatalErrSumm];
CREATE TABLE [Report]..[FatalErrSumm]
(
[MDF] NVARCHAR(255) NULL,
[Error] INT NULL,
);
END
END
This checks if Report exists from a different databse; if it does not exist it creates it, if it does, it checks if table FatalErrSumm exists and if it does it drops and recreates it.
The problems is that it seems to be executing both possiblities of the IF NOT EXISTS block and giving the error
Msg 2702, Level 16, State 2, Line 24
Database 'Report' does not exist.
when the database Report does not exist. So it should never be entering the ELSE block, however it seems to be. This is very basic stuff, but I cannot for the life of me spot the error, What am I doing wrong here?
Thanks for your time.
You should bypass it using a dynamic sql
IF NOT EXISTS (SELECT name
FROM sys.databases
WHERE name = N'Report')
BEGIN
DECLARE #DatabasePath NVARCHAR(1000);
SET #DatabasePath = (SELECT ResultMessage + '\'
FROM [Admin]..[Process]);
EXEC ispCREATEDB N'Report', #DatabasePath, N'10MB', N'20%'
END
ELSE IF DB_ID('Report') IS NOT NULL
EXEC
(
'BEGIN
IF EXISTS (SELECT *
FROM Report.sys.objects
WHERE name = N''FatalErrSumm'' AND type = N''U'')
BEGIN
DROP TABLE [Report]..[FatalErrSumm];
CREATE TABLE [Report]..[FatalErrSumm]
(
[MDF] NVARCHAR(255) NULL,
[Error] INT NULL,
);
END
END'
);
I think dynamic sql is the good solution for that. because in compile time compiler checked that the database "report" is not exist in you server.
If the report is offline I think this failes, check if the database is online /attached. There is flag for this in the sys.databases table.
Also do not put your statements in the ELSE. If you enter the 'THEN' part you create the database. After that check if it is created. Than ALWAYS check for you FATALERRSUMM table and not from the IF.
pseudo code:
if (not exists database) -- watch it not exists is really NOT EXISTS not just not online
create the database
if (exists database and not online)
put online the database
if (not exists database or not online database)
throw error
if (exists table fatalerrsum)
drop table
create table