Computed column based on nullable columns - sql

I want to create a computed column that is the concatenation of several other columns. In the below example, fulladdress is null in the result set when any of the 'real' columns is null. How can I adjust the computed column function to take into account the nullable columns?
CREATE TABLE Locations
(
[id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[fulladdress] AS (((([address]+[address2])+[city])+[state])+[zip]),
[address] [varchar](50) NULL,
[address2] [varchar](50) NULL,
[city] [varchar](50) NULL,
[state] [varchar](50) NULL,
[zip] [varchar](50) NULL
)
Thanks in advance

This gets messy pretty quick, but here's a start:
ISNULL(address,'') + ' '
+ ISNULL(address2,'') + ' '
+ ISNULL(city,'') + ' '
+ ISNULL(state,'') + ' '
+ ISNULL(zip,'')
(If isnull doesn't work, you can try coalesce. If neither work, share what DMBS you're using.)

You shouldn't have a full address column (which is a duplicate of other columns) stored in your database unless you have a good reason. The correct way would be to construct the full address string in your queries. By creating the field dynamically you reduce redundancy in the table and you have one less column to maintain (which would need to be updated anytime any other column changes).
In your query you would do something like
SELECT CONCAT(ISNULL(address,''), ISNULL(address2,''), ISNULL(city,''), ISNULL(state,''), ISNULL(zip,'')) AS fulladdress FROM Locations;
The CONCAT() function performs concatenation and the ISNULL() gives you your string if it's not null or the second param (which was passed as '') if it is null

Related

Add range values to include exiting table partition in Azure synapse Analytics

I need to add a new boundary value to the existing table .
CREATE TABLE [STG].[IHS_POLK]
(
[CCYYQ_NBR] [decimal](5, 0) NOT NULL,
[COUNTRY] [varchar](2) NOT NULL,
[STATE] [varchar](35) NOT NULL,
[COUNTY] [varchar](35) NOT NULL,
[ZIP] [varchar](6) NOT NULL,
[TOTAL] [varchar](10) NULL
)
WITH
(
DISTRIBUTION = ROUND_ROBIN,
CLUSTERED COLUMNSTORE INDEX,
PARTITION
([CCYYQ_NBR] RANGE LEFT FOR VALUES (20191, 20192, 20193, 20194, 20201, 20202, 20203, 20204, 20211, 20212, 20213, 20214, 20221, 20222, 20223, 20224, 20231, 20232, 20233, 20234, 20241, 20242, 20243, 20244, 20251, 20252, 20253, 20254))
)
GO
Now I need to add a value "20261" in the range . Please let me know the query to add.
You can use alter statement as below, if data exists in table, disable column store index before and rebuild it after running this. Refer this document for more details.
ALTER TABLE [STG].[IHS_POLK] SPLIT RANGE (20261);

SQL Server Prevent Update on Column (datetime2 column value set by database on insert)

I have a table Values with 3 columns:
CREATE TABLE [dbo].[Values]
(
[Id] [uniqueidentifier] NOT NULL,
[Value] [nvarchar](150) NOT NULL,
[CreatedOnUtc] [datatime2](7) NOT NULL
)
I want SQL Server to set the value of CreatedOnUtc to UTC-Now whenever a new entry is created, and not allow an external command to set this value.
Is this possible?
This is sort of two questions. For the first:
CREATE TABLE [dbo].[Values] (
[Id] [uniqueidentifier] NOT NULL,
[Value] [nvarchar](150) NOT NULL,
[CreatedOnUtc] [datetime2](7) NOT NULL DEFAULT SYSUTCDATETIME()
);
The canonical way to prevent changes to the column is to use a trigger that prevents the value from being updated or inserted.
Note that Values is a really bad name for a table because it is a SQL keyword and SQL Server reserved word. Choose identifiers that do not need to be escaped.
There are other ways. For instance, you could turn off DML access to the table. Then create a view without CreatedOnUtc and only allow inserts and updates through the view.

Sql Server - Insufficient result space to convert uniqueidentifier value to char

I am getting below error when I run sql query while copying data from one table to another,
Msg 8170, Level 16, State 2, Line 2
Insufficient result space to convert
uniqueidentifier value to char.
My sql query is,
INSERT INTO dbo.cust_info (
uid,
first_name,
last_name
)
SELECT
NEWID(),
first_name,
last_name
FROM dbo.tmp_cust_info
My create table scripts are,
CREATE TABLE [dbo].[cust_info](
[uid] [varchar](32) NOT NULL,
[first_name] [varchar](100) NULL,
[last_name] [varchar](100) NULL)
CREATE TABLE [dbo].[tmp_cust_info](
[first_name] [varchar](100) NULL,
[last_name] [varchar](100) NULL)
I am sure there is some problem with NEWID(), if i take out and replace it with some string it is working.
I appreciate any help. Thanks in advance.
A guid needs 36 characters (because of the dashes). You only provide a 32 character column. Not enough, hence the error.
You need to use one of 3 alternatives
1, A uniqueidentifier column, which stores it internally as 16 bytes. When you select from this column, it automatically renders it for display using the 8-4-4-4-12 format.
CREATE TABLE [dbo].[cust_info](
[uid] uniqueidentifier NOT NULL,
[first_name] [varchar](100) NULL,
[last_name] [varchar](100) NULL)
2, not recommended Change the field to char(36) so that it fits the format, including dashes.
CREATE TABLE [dbo].[cust_info](
[uid] char(36) NOT NULL,
[first_name] [varchar](100) NULL,
[last_name] [varchar](100) NULL)
3, not recommended Store it without the dashes, as just the 32-character components
INSERT INTO dbo.cust_info (
uid,
first_name,
last_name
)
SELECT
replace(NEWID(),'-',''),
first_name,
last_name
FROM dbo.tmp_cust_info
I received this error when I was trying to perform simple string concatenation on the GUID. Apparently a VARCHAR is not big enough.
I had to change:
SET #foo = 'Old GUID: {' + CONVERT(VARCHAR, #guid) + '}';
to:
SET #foo = 'Old GUID: {' + CONVERT(NVARCHAR(36), #guid) + '}';
...and all was good. Huge thanks to the prior answers on this one!
Increase length of your uid column from varchar(32) ->varchar(36)
because guid take 36 characters
Guid.NewGuid().ToString() -> 36 characters
outputs: 12345678-1234-1234-1234-123456789abc
You can try this. This worked for me.
Specify a length for VARCHAR when you cast/convert a value..for uniqueidentifier use VARCHAR(36) as below:
SELECT Convert (varchar(36),NEWID()) AS NEWID
The default length for VARCHAR datatype if we don't specify a length during CAST/CONVERT is 30..
Credit : Krishnakumar S
Reference : https://social.msdn.microsoft.com/Forums/en-US/fb24a153-f468-4e18-afb8-60ce90b55234/insufficient-result-space-to-convert-uniqueidentifier-value-to-char?forum=transactsql

Creating trigger in SQL Server 2005 (has to work in 2008 too) to prevent duplicates?

I have table that I insert data with following query (from c# code):
INSERT INTO [BazaZarzadzanie].[dbo].[Wycena]
([KlienciPortfeleKontaID]
,[WycenaData]
,[WycenaTyp]
,[WycenaWartosc]
,[WycenaWaluta]
,[WycenaUzytkownik]
,[WycenaUzytkownikData])
VALUES
(#varKlienciPortfeleKontaID
,#varWycenaData
,#varWycenaTyp
,#varWycenaWartosc
,#varWycenaWaluta
,#varWycenaUzytkownik
,#varWycenaUzytkownikData)
Table creation script looks like this:
CREATE TABLE [dbo].[Wycena](
[KlienciPortfeleKontaID] [int] NULL,
[WycenaData] [datetime] NULL,
[WycenaTyp] [int] NULL,
[InID] [int] NULL,
[WycenaIlosc] [decimal](18, 2) NULL,
[WycenaCena] [decimal](18, 2) NULL,
[WycenaWartosc] [decimal](18, 2) NULL,
[WycenaWaluta] [nvarchar](3) NULL,
[WycenaUzytkownik] [nvarchar](50) NULL,
[WycenaUzytkownikData] [datetime] NULL
) ON [PRIMARY]
It also has couple of foreign keys but nothing that i could make primary/unique key. So i thought to prevent duplicates i would go for a trigger since to know one row is duplicate i actually have to test every single value of that row (well maybe not 2 last columns) ? This table has around 2mln rows.
Is this good idea? Or is there a better way?
Below is trigger I've created (not tested if it works):
CREATE TRIGGER [dbo].[trg_WycenaDuplicateCheck]
ON [dbo].[Wycena] FOR INSERT
AS
IF EXISTS(SELECT INSERTED.[KlienciPortfeleKontaID]
,INSERTED.[WycenaData]
,INSERTED.[WycenaTyp]
,INSERTED.[InID]
,INSERTED.[WycenaIlosc]
,INSERTED.[WycenaCena]
,INSERTED.[WycenaWartosc]
,INSERTED.[WycenaWaluta]
FROM INSERTED, Wycena
WHERE INSERTED.[KlienciPortfeleKontaID] = Wycena.[KlienciPortfeleKontaID]
AND INSERTED.[WycenaData] = Wycena.[WycenaData]
AND INSERTED.[WycenaTyp] = Wycena.[WycenaTyp]
AND INSERTED.[InID] = Wycena.[InID]
AND INSERTED.[WycenaIlosc] = Wycena.[WycenaIlosc]
AND INSERTED.[WycenaCena] = Wycena.[WycenaCena]
AND INSERTED.[WycenaWartosc] = Wycena.[WycenaWartosc]
AND INSERTED.[WycenaWaluta] = Wycena.[WycenaWaluta]
Group By INSERTED.[KlienciPortfeleKontaID]
,INSERTED.[WycenaData]
,INSERTED.[WycenaTyp]
,INSERTED.[InID]
,INSERTED.[WycenaIlosc]
,INSERTED.[WycenaCena]
,INSERTED.[WycenaWartosc]
,INSERTED.[WycenaWaluta]
HAVING COUNT (*) > 1)
BEGIN
RAISERROR('>>>DUPLICATES PREVENTED<<< ',10,1)
ROLLBACK TRAN
END
Create a "unique" index on the fields you care about.
CREATE UNIQUE INDEX IX_YOUR_FAVORITE_NAME
ON [dbo].[Wycena](... list of columns goes here ...)
Seems like you need to look at UNIQUE Constraints

Regex to extract fields and data types from sql statement

I have this sql statement:
CREATE TABLE [dbo].[User]( [UserId] [int] IDENTITY(1,1) NOT NULL,
[FirstName] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [MiddleName]
[varchar](50) COLLATE SQL_Latin1_General_CP1_CI_A
What i want is regex code which i can use to get all fields and data type.
So will return something like that:
FirstName varchar
MiddleName varchar
Notes:
The sql statement will always have this format.
I am using .Net to run this regex
You didn't mention whether the SQL statement is in a string on one line or if it's spanning multiple lines.
Assuming it's on one line, this may fit your request:
Dim input As String = "CREATE TABLE [dbo].[User]( [UserId] [int] IDENTITY(1,1) NOT NULL, " & _
"[FirstName] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [MiddleName] " & _
"[varchar](50) COLLATE SQL_Latin1_General_CP1_CI_A"
For Each m As Match In Regex.Matches(input, "\[(?<Field>\w+)\]\s*\[(?<Type>\w+)\]")
Console.WriteLine("{0} : {1}", m.Groups("Field").Value, m.Groups("Type").Value)
Next
I don't know anything .NET. In some other worlds, the following could handle the search portion of the operation:
\[(.*?)\][\s\n\r]+\[(.*?)\]\((\d\d)\)
Insert that into the "search" format for a .NET regex (whatever that might be), write your output stuff. If linebreaks can occur midword then this could have problems. Note that the above also pulls the type's length, so it would produce
MiddleName varchar 50
To do without the third backreference, just leave it out of the replace (wasted) or do
\[(.*?)\][\s\n\r]+\[(.*?)\]\(\d\d\)
Lots of fine ways to do it. As usual just make sure you understand the potential variability of the input.