Why columns value change into NULL when try to update only one column? - sql

This is my table which I created in sql server...
CREATE TABLE [dbo].[Addresses_Table](
[AddressID] [int] IDENTITY(1,1) NOT NULL,
[BuildingName] [varchar](300) NULL,
[UnitNumber] [nvarchar](50) NULL,
[StreetNumber] [varchar](20) NULL,
[StreetName] [varchar](200) NULL,
[Suburb] [varchar](100) NULL,
[POBox] [varchar](20) NULL,
CONSTRAINT [PK_Addresses_Table] PRIMARY KEY CLUSTERED (
[AddressID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = OFF, ALLOW_PAGE_LOCKS = OFF) ON [PRIMARY] ) ON [PRIMARY]
INSERT INTO [dbo].[Addresses_Table] (BuildingName,UnitNumber,StreetNumber, StreetName, Suburb) VALUES ('mybuilding', '101', '12','Street 1', 'TEST12')
When I try to update 'POBox' column value into '1234' (any value),
BuildingName, UnitNumber, StreetNumber, StreetName turn into NULL values.
I have attached my sql update query and results of it.
Please help me out to solve this problem....

It seems there is a trigger on the table that sets StreetName to NULL after the update. This is evidenced by the SSMS output that shows 2 rowcount messages, one when the row is updated directly and the other when the same row is updated by the trigger.
The trigger makes sense from a data perspective since StreetName does not apply to a PO box address.

Related

Clustered Index Update Slow Update On Large Table

I am having a problem updating a large table with millions of rows please advice to reduce the update time.
Table definition
CREATE TABLE [dbo].[tbl_sms_job_detail](
[JobDetailID] [int] IDENTITY(1,1) NOT NULL,
[JobID] [int] NULL,
[DistributorID] [int] NULL,
[ResellerID] [int] NULL,
[CustomerID] [int] NULL,
[SenderID] [nvarchar](50) NULL,
[PhoneNumber] [nvarchar](100) NULL,
[SMSMessage] [nvarchar](1000) NULL,
[MessageType] [nvarchar](50) NULL,
[MessageLength] [int] NULL,
[MessageParts] [int] NULL,
[ClientRate] [decimal](18, 5) NULL,
[ClientCost] [decimal](18, 5) NULL,
[ResellerRate] [decimal](18, 5) NULL,
[ResellerCost] [decimal](18, 5) NULL,
[DistributorRate] [decimal](18, 5) NULL,
[DistributorCost] [decimal](18, 5) NULL,
[RouteDetailID] [int] NULL,
[SMSID] [nvarchar](200) NULL,
[DLRStatus] [nvarchar](100) NULL,
[ErrorCode] [int] NULL,
[ErrorDescription] [nvarchar](2000) NULL,
[SentDate] [datetime] NULL,
[SentDateUTC] [datetime] NULL,
[SMSSource] [nvarchar](50) NULL,
[SMSType] [nvarchar](100) NULL,
[APISMSID] [int] NULL,
[DLRDate] [datetime] NULL,
[DLRDateUTC] [datetime] NULL,
CONSTRAINT [PK_tbl_sms_job_detail] PRIMARY KEY CLUSTERED
(
[JobDetailID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [NonClusteredIndex-20170919-173756] ON [dbo].[tbl_sms_job_detail] ( [JobID] ASC, [DLRStatus] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) GO
CREATE NONCLUSTERED INDEX [NonClusteredIndex-20170919-174142] ON [dbo].[tbl_sms_job_detail]
(
[SMSID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
Update Procedure
CREATE Procedure [dbo].[sp_update_message_status]
#SMSID nvarchar(200),
#DLRStatus nvarchar(100),
#ErrorCode int,
#ErrorDescription nvarchar(2000)
AS
UPDATE tbl_sms_job_detail SET DLRStatus = #DLRStatus, ErrorCode = #ErrorCode, ErrorDescription = #ErrorDescription WHERE SMSID = #SMSID
Execution Plan
This Procedure is called up to 1000 times in several minutes and some of them fail to update as it takes time to update the previous record what can be done to increase the update of a record in this table.
I suspect that the issue is not being caused by the actual clustered index but by the effect the update query has.
MSSQL is a page based storage system. When adding records to the table, as the clustered index is on the field [JobDetailID] [int] IDENTITY(1,1) NOT NULL, each new record is applied to the last page currently at the table (if it will fit) or a new page is tacked onto the end of the table and the record stored in it.
Assuming that [DLRStatus] and/or [ErrorDescription] start of a null or empty strings, when the update sproc runs, it has to find some space in the page that the record is already in to store the new value in. SQL keeps a little space in each page file for such purpose, but when that space is used up, it will have to do a page split - splitting the contents of the one page file into the existing page file and a newly created blank page file. As the primary key is clustered, this new page file has to be inserted so it keeps the records stored in the table in the clustered index order. It is quite likely that this page splitting is at the root of the problem.
The amount of space that SQL keeps back before creating a new page is configurable, therefore one solution is to initially create the page files with plenty of 'expansion' room. On an index it is called the fill factor, but I am not sure what the correct term is for data pages (probably still a fill factor, but not sure).
Another alternative is to store the returned error information in a separate table and then store the primary key for the 'error information' record in table [tbl_sms_job_detail]. As long as the key is not a nvarchar / varchar (and who would do this anyway), the space required in the page file will already be reserved. Thus recording the error information requires appending the variable text information to the end of the last page file for the new table and updating a foreign key in your original table that already has space reserved for it and so doesn't trigger of a page slit.

create a constraint on a column, but only for a part of the data

I want to create a constraint on a column, but only for a part of the data.
The situation is this: we have all the values for all dropdowns in one table. To separate them we have a discriminator called dropdowntype.
Now I want to create a constraint, but it has to take the dropdowntype into account.
The constraint is: dropdowns can have a default value. There is only zero or one record allowed, per dropdowntype, which has the value true for isdefault.
So there can be multiple records with the value true for isdefault, but they should all have a different value for dropdowntype.
EDIT:There are however multiple values allowed for a given dropdowntype with the value false.
Is this possible to do?
(then as a bonus, I would also like to put a constraint on another nullable column, that all values for that column are either null or have a value, again for a given dropdowntype. But maybe when the first question is answered, I'll figure out how to do this one myself.)
Table:
CREATE TABLE [dbo].[DropDownValues](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[CreateDate] [datetime] NOT NULL,
[IsActive] [bit] NOT NULL,
[IsDefaultValue] [bit] NOT NULL,
[Description] [nvarchar](1000) NULL,
[IsOtherItem] [bit] NOT NULL,
[Dropdowntype] [tinyint] NOT NULL,
CONSTRAINT [PK_ddv] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
To answer question 1, you want a compound unique key on dropdowntype and isdefault. Pseudo code:
CREATE UNIQUE NONCLUSTERED INDEX idx_yourcolumn_notnull
ON YourTable(dropdowntype, isdefault)
WHERE isdefault IS NOT NULL;
You can do the same for the 2nd part of your question. They key is the WHERE isDefault IS NOT NULL, ths allows you to create a unique constraint on a nullable column.

Conversion failed when converting the varchar value 'a' to data type int

Something must be wrong with my ADDRESS table's definition. When inserting or selecting rows, it is treating the LINE1 column as int, but clearly I have declared it as varchar(128).
This command works fine:
insert into address(PERSON_ID, LINE1, TYPE_ID)
values (234, 'a', 1)
But in SQL Server Management Studio, when I do "Edit top 200 rows" and try to insert the same values, I get an error message.
After having inserted via SQL query, selecting rows from the table gives same error message.
Error message I get when inserting via SSMS Edit rows feature, or C#, and when selecting:
Conversion failed when converting the varchar value 'a' to data type int.
ADDRESS table:
CREATE TABLE [dbo].[ADDRESS]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[PERSON_ID] [int] NOT NULL,
[LINE1] [varchar](128) NOT NULL,
[LINE2] [varchar](128) NULL,
[CITY] [varchar](256) NULL,
[COUNTY_ID] [int] NULL,
[STATE] [int] NULL,
[POSTAL_CODE] [varchar](16) NULL,
[COUNTRY_ID] [int] NULL,
[TYPE_ID] [int] NOT NULL,
[DESCRIPTION] AS ([dbo].[GET_ADDRESS_STRING]([ID])),
CONSTRAINT [PK_ADDRESS]
PRIMARY KEY CLUSTERED ([ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

enforce primary key to exist in another multi colum primary key

I have two tables. First table has multi columns as the primary key and the second table has one column primary key. Data has be entered first in Table1 FieldPlacement where FieldPlacementNum will be generated then enter a record in Table2 where the FieldPlacementNum has to exist in Table1.
Currently has one to many relationship but I want the reverse the relationship of tables and SQL does not let me do it. thanks
Table 1
CREATE TABLE [dbo].[FieldPlacement]
(
[ID] [varchar](10) NOT NULL,
[Year] [varchar](10) NOT NULL,
[Term] [varchar](10) NOT NULL,
[PlacementNum] [int] IDENTITY(1,1) NOT NULL,
[Email] [varchar](70) NULL,
CONSTRAINT [PK_FieldPlacement]
PRIMARY KEY CLUSTERED ([ID] ASC, [Year] ASC, [Term] ASC, [PlacementNum] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[FieldPlacement] WITH CHECK
ADD CONSTRAINT [FK_FieldPlacement_FieldPlacementEval1]
FOREIGN KEY([PlacementNum])
REFERENCES [dbo].[FieldPlacementEval] ([PlacementNum])
GO
ALTER TABLE [dbo].[FieldPlacement]
CHECK CONSTRAINT [FK_FieldPlacement_FieldPlacementEval1]
GO
Table 2
CREATE TABLE [dbo].[FieldPlacementEval]
(
[PlacementNum] [int] NOT NULL,
[StudentLastName] [varchar](50) NULL,
[StudentFirstName] [varchar](50) NULL,
[TeacherLastName] [varchar](50) NULL,
[TeacherFirstName] [varchar](50) NULL,
CONSTRAINT [PK_FieldPlacementEval]
PRIMARY KEY CLUSTERED ([PlacementNum] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Since FieldPlacement.PlacementNum is an IDENTITY, which is NOT NULL and unique, you could also make this your PK, and then just create a unique index on those four columns that currently make up the PK (to ensure their uniqueness).
From your FieldPlacementEval just reference the PlacementNum.
The additional benefit here would be a smaller, more efficient clustering key on your FieldPlacement table (since it's only 1 column instead of 4 - and skips all those variable length columns which are really bad for a clustering key)

How to Insert into 2 Tables ProductOrder and ProductOrderLine using VBA & Foreign Keys in Excel

I am newbiew using VBA/FK/SQL server all in one. I am creating simple purchase order workbook user interface in excel.
I have created two tables:
CREATE TABLE [dbo].[PurchaseOrder](
[PKPurchaseOrderID] [bigint] IDENTITY(1,1) NOT NULL,
[PurchaseOrderNumber] [bigint] NULL,
[PurchaseOrderDate] [date] NULL,
[PurchaseOrderTime] [int] NULL,
[PurchaseOrderSupplierID] [nvarchar](50) NULL,
[ShipToA1] [nvarchar](50) NULL,
[ShipToA2] [nvarchar](50) NULL,
[ShipToA3] [nvarchar](50) NULL,
[ShipToA4] [nvarchar](50) NULL,
CONSTRAINT [PK_PurchaseOrder] PRIMARY KEY CLUSTERED
(
[PKPurchaseOrderID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
and
CREATE TABLE [dbo].[PurchaseOrderLines](
[PKPurchaseOrderLineID] [bigint] IDENTITY(1,1) NOT NULL,
[FKPurchaseOrderID] [bigint] NULL,
[Quantity] [smallint] NULL,
[Item] [nchar](25) NULL,
[Description] [nvarchar](50) NULL,
[siteID] [nchar](10) NULL,
[UnitPrice] [money] NULL,
[LineTotal] [money] NULL,
CONSTRAINT [PK_PurchaseOrderLines] PRIMARY KEY CLUSTERED
(
[PKPurchaseOrderLineID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[PurchaseOrderLines] WITH CHECK ADD CONSTRAINT
[FK_PurchaseOrderLines_PurchaseOrder] FOREIGN KEY([FKPurchaseOrderID])
REFERENCES [dbo].[PurchaseOrder] ([PKPurchaseOrderID])
ALTER TABLE [dbo].[PurchaseOrderLines] CHECK CONSTRAINT
[FK_PurchaseOrderLines_PurchaseOrder]
GO
I want to achieve that in the background when user clicks the button both tables are updated.
I am not sure how I can link brand new row created in the PurchaseOrder table with FK in the PurchaseorderLine table.
What i plan to do for single user interface:
Insert New Order
Use Max(PKPurchaseOrderID) as FK for new order lines table.
How can I determine currently inserted Order ID(PKPurchaseOrderID) if multiple users are working/submitting orders at the same time. I am afraid order lines may be assigned to different orders if I use my plan. e.g.
Please advise.
I use SQL Server 2008 and Excel 2007/2010
Many thanks
I would create a stored procedure that inserts the new row and returns the ID with SCOPE_IDENTITY()
Here's a decent article on the different "identity" methods in SQL Server.
http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/