Insert statement with a NON-NULLABLE column - sql

I have a SQL Server script that I'm using to insert some data into a database. I won't upload the whole script here just for space/time savings sake, but I will include the important bits.
So here is the problem. I have a table that has a column for some loginhtml, this column is of a non-nullable type. I would like for this column to be left blank on this particular add so it can default back to the parent that I'm pointing it at. So here we have the declaration for this important portion:
declare #loginTitle varchar(250), #loginHtml varchar(max)
And here we have what it will be set to:
set #loginHtml = null
And here is the insert part that is inevitably going to fail:
insert dbo.ApplicationLogin(ApplicationID, Title, Html)
select #appID, #loginTitle, #loginHtml
EDIT: How can I have this script "default" the loginhtml column to whatever the PARENT Application is? Is there some "IF" statement/clause that can be used to accomplish this?

As long as the column in non null, then you can't insert a null value into it. You could try setting it to a blank string or other default value. You could aslo select the parent's html and insert that instead. There is no way to skip over inserting any column.

As others have stated, if there is a Not Null constraint on the column, you are out of luck, but you could do
if #loginhtml is null
begin
set #loginhtml = ''
end
Or change
set #loginhtml = ''
to lookup whatever the default in the parent application is.
and you will write a blank instead of anything. You, obviously, run into whatever issues there will be with having no loginhtml, but if that's what you want that is what you want!

You can adjust your script:
insert dbo.ApplicationLogin(ApplicationID, Title, Html)
select #appID, #loginTitle, ISNULL(#loginHtml, '')
Or adjust your table and add a default constraint:
ALTER TABLE ApplicationLogin ADD DEFAULT (('')) FOR [Html];

I may not have mentioned this in the initial post, and I would like to apologize for that. But the way the database is set up, is applications can have parent applications, so setting the loginhtml to the parent application and "technically" skipping adding it to the new application can be done by doing this:
if(#loginHtml is not null)
begin
insert dbo.ApplicationLogin(ApplicationID, Title, Html)
select #appID, #loginTitle, #loginHtml
end
This runs successfully and makes the "#loginhtml" default to whatever the parent application has set for that value.

Related

Creating a sequence on an existing table

How can I create a sequence on a table so that it goes from 0 -> Max value?
I've tried using the following SQL code, but it does not insert any values into the table that I am using:
CREATE SEQUENCE rid_seq;
ALTER TABLE test ADD COLUMN rid INTEGER;
ALTER TABLE test ALTER COLUMN rid SET DEFAULT nextval('rid_seq');
The table I am trying to insert the sequence in is the output from another query. I can't figure out if it makes more sense to add the sequence during this initial query, or to add the sequence to the table after the query is performed.
Set the default value when you add the new column:
create sequence rid_seq;
alter table test add column rid integer default nextval('rid_seq');
Altering the default value for existing columns does not change existing data because the database has no way of knowing which values should be changed; there is no "this column has the default value" flag on column values, there's just the default value (originally NULL since you didn't specify anything else) and the current value (also NULL) but way to tell the difference between "NULL because it is the default" and "NULL because it was explicitly set to NULL". So, when you do it in two steps:
Add column.
Change default value.
PostgreSQL won't apply the default value to the column you just added. However, if you add the column and supply the default value at the same time then PostgreSQL does know which rows have the default value (all of them) so it can supply values as the column is added.
By the way, you probably want a NOT NULL on that column too:
create sequence rid_seq;
alter table test add column rid integer not null default nextval('rid_seq');
And, as a_horse_with_no_name notes, if you only intend to use rid_seq for your test.rid column then you might want to set its owner column to test.rid so that the sequence will be dropped if the column is removed:
alter sequence rid_seq owned by test.rid;
In PostgreSQL:
UPDATE your_table SET your_column = nextval('your_sequence')
WHERE your_column IS NULL;
I'm not fluent in postgresql so I'm not familiar with the "CREATE SEQUENCE" statement. I would think, though, that you're adding the column definition correctly. However, adding the column doesn't automatically insert data for existing rows. A DEFAULT constraint is for new rows. Try adding something like this afterwards to populate data on the existing rows.
DECLARE #i Int
SET #i = 0
SET ROWCOUNT 1
WHILE EXISTS (SELECT 1 FROM test WHERE rid IS NULL) BEGIN
UPDATE test SET rid = #i WHERE rid IS NULL
END
SET ROWCOUNT 0

SQL Trigger to update row

I need a SQL trigger that would zero pad a cell whenever its inserted or updated. Was curious if its best practice to append two strings together like I'm doing in the update command. Is this be best way to do it?
CREATE TRIGGER PadColumnTenCharsInserted ON Table
AFTER INSERT
AS
DECLARE
#pad_characters VARCHAR(10),
#target_column NVARCHAR(255)
SET #pad_characters = '0000000000'
SET #target_column = 'IndexField1'
IF UPDATE(IndexField1)
BEGIN
UPDATE Table
SET IndexField1 = RIGHT(#pad_characters + IndexField1, 10)
END
GO
Your padding code looks fine.
Instead of updating every row in the table like this:
UPDATE Table
update just the row that triggered the trigger:
UPDATE updated
Also, you've still got some extraneous code -- everything involving #target_column. And it looks like you're not sure if this is an INSERT trigger or an UPDATE trigger. I see AFTER INSERT and IF UPDATE.
Two questions:
What are you doing with #target_column? You declare it and set it with a column name, but then you never use it. If you intend to use the variable in your subsequent SQL statements, you may need to wrap the statements in an EXECUTE() or use sp_executesql().
The syntax "UPDATE Table..." is OK for your update statement assuming that "Table" is the name of the table you are updating. What seems to be missing is a filter of some kind. Or did you really intend for that column to be updated for every row in the whole table?
One way to handle this would be to declare another variable and set it with the PK of the row that is updated, then use a where clause to limit the update to just that row. Something like this:
DECLARE #id int
SELECT #id = Record_ID FROM INSERTED
-- body of your trigger here
WHERE Record_ID = #id
I like your padding code. It looks good to me.

Help with SQL Server Trigger to truncate bad data before insert

We consume a web service that decided to alter the max length of a field from 255. We have a legacy vendor table on our end that is still capped at 255. We are hoping to use a trigger to address this issue temporarily until we can implement a more business-friendly solution in our next iteration.
Here's what I started with:
CREATE TRIGGER [mySchema].[TruncDescription]
ON [mySchema].[myTable]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [mySchema].[myTable]
SELECT SubType, type, substring(description, 1, 255)
FROM inserted
END
However, when I try to insert on myTable, I get the error:
String or binary data would be
truncated. The statement has been
terminated.
I tried experimenting with SET ANSI_WARNINGS OFF which allowed the query to work but then simply didn't insert any data into the description column.
Is there any way to use a trigger to truncate the too-long data or is there another alternative that I can use until a more eloquent solution can be designed? We are fairly limited in table modifications (i.e. we can't) because it's a vendor table, and we don't control the web service we're consuming so we can't ask them to fix it either. Any help would be appreciated.
The error cannot be avoided because the error is happening when the inserted table is populated.
From the documentation:
http://msdn.microsoft.com/en-us/library/ms191300.aspx
"The format of the inserted and deleted tables is the same as the format of the table on which the INSTEAD OF trigger is defined. Each column in the inserted and deleted tables maps directly to a column in the base table."
The only really "clever" idea I can think of is to take advantage of schemas and the default schema used by a login. If you can get the login that the web service is using to reference another table, you can increase the column size on that table and use the INSTEAD OF INSERT trigger to perform the INSERT into the vendor table. A variation of this is to create the table in a different database and set the default database for the web service login.
CREATE TRIGGER [myDB].[mySchema].[TruncDescription]
ON [myDB].[mySchema].[myTable]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [VendorDB].[VendorSchema].[VendorTable]
SELECT SubType, type, substring(description, 1, 255)
FROM inserted
END
With this setup everything works OK for me.
Not to state the obvious but are you sure there is data in the description field when you are testing? It is possible they change one of the other fields you are inserting as well and maybe one of those is throwing the error?
CREATE TABLE [dbo].[DataPlay](
[Data] [nvarchar](255) NULL
) ON [PRIMARY]
GO
and a trigger like this
Create TRIGGER updT ON DataPlay
Instead of Insert
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [tempdb].[dbo].[DataPlay]
([Data])
(Select substring(Data, 1, 255) from inserted)
END
GO
then inserting with
Declare #d as nvarchar(max)
Select #d = REPLICATE('a', 500)
SET ANSI_WARNINGS OFF
INSERT INTO [tempdb].[dbo].[DataPlay]
([Data])
VALUES
(#d)
GO
I am unable to reproduce this issue on SQL 2008 R2 using:
Declare #table table ( fielda varchar(10) )
Insert Into #table ( fielda )
Values ( Substring('12345678901234567890', 1, 10) )
Please make sure that your field is really defined as varchar(255).
I also strongly suggest you use an Insert statement with an explicit field list. While your Insert is syntactically correct, you really should be using an explicit field list (like in my sample). The problem is when you don't specify a field list you are at the mercy of SQL and the table definition for the field order. When you do use a field list you can change the order of the fields in the table (or add new fields in the middle) and not care about your insert statements.

SQL Server 2008 stored procedure result as column default value

First of all, thank you guys. You always know how to direct me when I can't even find the words to explain what the heck I'm trying to do.
The default values of the columns on a couple of my tables need to be equal the result of some complicated calculations on other columns in other tables. My first thought is to simply have the column default value equal the result of a stored procedure. I would also have one or more of the parameters pulled from the columns in the calling table.
I don't know the syntax of how to do it though, and any time the word "stored" and "procedure" land next to each other in google I'm flooded with info on Parameter default values and nothing relating to what I actually want.
Half of that was more of a vent than a question...any ideas though? And plz plz don't say "Well, you could use an On-Insert Trigger to..."
You can't have the default be the result of a stored procedure, it has to be a function. If you can convert the procedure into a function, then you can use that function. If you cannot, then you must use a trigger.
You would have to convert that stored procedure to a user-defined function. There are different types of UDF's - the one you're looking at would be the scalar UDF - returning a single value.
So for instance you could create a function like this:
CREATE FUNCTION dbo.YourDefaultFunction(#Input1 INT, #Input2 VARCHAR(10))
RETURNS VARCHAR(100)
AS BEGIN
DECLARE #Result VARCHAR(100)
SET #Result = #Input2 + ' - giving: ' + CAST(#Input1 AS VARCHAR(5))
RETURN #Result
END
Of course, yours would be a lot more complicated :-)
Once you've done that, you can define this to be the default for a column of type VARCHAR(100) - either directly when declaring the table, or later on via an ALTER TABLE statement:
CREATE TABLE dbo.YourTable(.......
SomeColumn VARCHAR(100)
CONSTRAINT DF_YourTable_SomeColumn
DEFAULT (dbo.YourDefaultFunction(417, 'Test')),
.....)
or :
ALTER TABLE dbo.YourTable
ADD CONSTRAINT DF_YourTable_SomeColumn
DEFAULT (dbo.YourDefaultFunction(4711, 'Test2'))
FOR SomeColumn
Unfortunately, you cannot pass other columns as parameters to your function when defining it as a default value for a column.
Does that help??

Inserting "null" (literally) in to a stored procedure parameter

I'm trying to insert the word "Null" (literally) in to a parameter for a stored procedure. For some reason SqlServer seems to think I mean NULL and not "Null". If I do a check for
IF #LastName IS NULL // Test: Do stuff
Then it bypasses that because the parameter isn't null.
But when I do:
INSERT INTO Person (<params>) VALUES (<stuff here>, #LastName, <more stuff here>); // LastName is 'Null'
It bombs out saying that LastName doesn't accept nulls.
I would seriously hate to have this last name, but someone does... and it's bombing the application. We're using SubSonic 2.0 (yeah, it's fairly old but upgrading is painful) as our DAL and stepping through it, I see it does create the parameters properly (for what I can tell).
I've tried creating a temp table to see if I could replicate it manually but it seems to work just fine. Here is the example I create:
DECLARE #myval VARCHAR(50)
SET #myval = 'Null'
CREATE TABLE #mytable( name VARCHAR(50))
INSERT INTO #mytable VALUES (#myval)
SELECT * FROM #mytable
DROP table #mytable
Any thoughts on how I can fix this?
edit: The method the LastName is set is this -- myPerson.LastName = textBoxLastName.Text;
edit: Upon using SqlServer Profiler, I see that it IS sending null. Two things that's weird, I wonder why my "IF #lastName IS NULL" isn't firing off... but now I have to look at SubSonic further to see if something is changing last minute I wasn't aware of. I'll investigate this further and report back.
edit: The only constraint is a default value of ''.
edit: Ok, I've confirmed it IS SubSonic trying to play smart.
if (param.ParameterValue == null || Utility.IsMatch(param.ParameterValue.ToString(), "null"))
Good idea for using the Profiler, I entirely forgot about that.
final edit: It's worth noting, fur future reference, that SubSonic replaces this at the last minute in the data provider (in my case SqlDataProvider). In The DataService.cs where it calls Execute Scalar, the parameters have not been adjusted yet. They get adjusted when it runs the ExecuteScalar for the DataProvider, which is an abstract class (so Postgre and Oracle will each have their own bits of code). Specifically, the SubSonic.SqlDataProvider.AddParams is what bit me.
It's worth noting, fur future reference, that SubSonic replaces this at the last minute in the data provider (in my case SqlDataProvider). In The DataService.cs where it calls Execute Scalar, the parameters have not been adjusted yet. They get adjusted when it runs the ExecuteScalar for the DataProvider, which is an abstract class (so Postgre and Oracle will each have their own bits of code). Specifically, the SubSonic.SqlDataProvider.AddParams is what bit me.
Please try this:
Oops...I totally misunderstood the question. I think there should be some constraints set in the database column. Please try to write the insert query directly in DB and see if it bombs out.
I tried this and it bombs out as expected:
DECLARE #myval VARCHAR(50)
SET #myval = 'null'
CREATE TABLE #mytable( name VARCHAR(50) NULL CHECK (name <> 'NULL'))
INSERT INTO #mytable VALUES (#myval)
SELECT * FROM #mytable WHERE name is not null
DROP table #mytable
HTH