I'm using SQL Server 2008 R2. I want to create an auto-generated customer id whenever a new customer is registered. The customer id should be in the following format
Customer ID =
current year (4 digit) +
current month (2 digit) +
unique number (4 digit).
Example: 2012055001
I have written a query as follows:
create table tb
(
id int identity(1000, 1),
cust_id as CONVERT(VARCHAR(4), DATEPART(YYYY, GETDATE())) +
SUBSTRING(CONVERT(nvarchar(6), GETDATE(), 112), 5, 2) +
CONVERT(VARCHAR(4), id) persisted primary key
);
But I'm getting the following error:
Computed column 'cust_id' in table 'tb' cannot be persisted because the column is non-deterministic.
How do I rectify this problem?
You're confusing structure with data. You're trying to create your table with data as the structure type, and that clearly can't work.
The column name would be cust_id, but the column type has to be one of the valid SQL Server data types (in this case most likely CHAR(10), as it's a fixed width and there are no Unicode characters possible).
CREATE TABLE tb(id int identity(1000, 1), cust_id Char(10));
Your auto-generated data would then be inserted into the column, most likely by an ON INSERT trigger. (How to create that trigger is a totally different topic; you can find information in most SQL tutorials or books, or in SQL Server documentation.)
Related
I have a column in my table that is of float type. The table was automatically generated when I imported the spreadsheet (Excel) data to my database. Thus there is a column I wish to change from float to varchar, but when I try to do this, I get an error:
'tblInvoices' table
Unable to create index 'IX_tblInvoices'.
The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'dbo.tblInvoices' and the index name 'IX_tblInvoices'.
The duplicate key value is (1.00001e+006). The statement has been terminated.
It is a unique column, and set that way (not set as the primary key for reasons). I have already run queries to search for and delete duplicate fields but there are none. The query I ran as follows:
WITH CTE AS
(
SELECT
Invoice,
RN = ROW_NUMBER()OVER(PARTITION BY Invoice ORDER BY Invoice)
FROM
dbo.tblInvoices
)
DELETE FROM CTE
WHERE RN > 1
So the value within the Invoice column is 1000010 and when I run the following query a single row is found.
SELECT *
FROM [TradeReceivables_APR_IFRS9].[dbo].[tblInvoices]
WHERE Invoice = 1.00001e+006
Note that I have searched for the value in the error, 1.00001e+006, and not 1000010.
So my question is why does the DBMS do this? Why does it change the value like that? When I remove the column, it does it with another column and so on and so on (about 40 000 rows in total). How can I change the column from float to varchar without changing the data and getting errors?
Any help will be greatly appreciated!
It seems that the field is an integer so you can Cast it to BIGINT before cast to VARCHAR
Declare #Invoice as float = 1.00001e+006
print cast(#Invoice as varchar) -->> Result : 1.00001e+006
print cast(cast(#Invoice as bigint) as varchar) -->> Result : 1000010
I'm trying a really novice MS Access form (linked to) with a SQL Server in the backend.
So I have a simple table for invoices created with
create table Invoice
(
ID INT not null primary key,
IssuerID int not null,
InvoiceID int not null,
CustomerID int not null
)
Maybe I even do not need an ID, since I can uniquely identify entries by pairs (IssuerID, InvoiceID).
All in all, I want to add invoice by IssuerID to some CustomerID and InvoiceID should naturally increment by 1. I can do something like
SELECT ISNULL(MAX(InvoiceID), 0) + 1 AS InvoiceID
FROM Invoice
WHERE IssuerID = #sp;
where #sp is some value.
In the UI logic, I have a combobox to pick IssuerID (ACCESS) and here my problem begin.
I've used a textbox for InvoiceID. I want it to update the table by the next ID (i.e. if IssuerID = 5, had 3 issued invoices, next invoice should be numbered 4).
I was not able to make direct SQL work, nor by using VBA in after_update on IssuerID combo.
So I've created a view (in SQL Server and linked to it) with all possible IssuerIds and their appropriate nextInvoiceIds.
SELECT
IssuerID, NextInvoiceID
FROM
(SELECT
Issuers.ID AS IssuerID,
ISNULL(MAX(Invoice.InvoiceID), 0) + 1 AS NextInvoiceID
FROM
Issuers
FULL OUTER JOIN
Invoice ON Issuers.ID = Invoice.IssuerID
GROUP BY
Issuers.ID) AS UNDATA
Next, I was able to pick nextInvoiceID, but now I need it to also update the actual column back.
Is it possible from the same textbox?
Should I instead fallback to update this (InvoiceID) with some trigger (or are there other auto-increment options available in SQL Server)?
I have a SELECT that retrieves ROWS comparing a DATETIME field to the highest available value of another TABLE.
The Two Tables have the following structure
DeletedRecords
- Id (Guid)
- RecordId (Guid)
- TableName (varchar)
- DeletionDate (datetime)
And Another table which keep track of synchronizations using the following structure
SynchronizationLog
- Id (Guid)
- SynchronizationDate (datetime)
In order to get all the RECORDS that have been deleted since the last synchronization, I run the following SELECT:
SELECT
[Id],[RecordId],[TableName],[DeletionDate]
FROM
[DeletedRecords]
WHERE
[TableName] = '[dbo].[Person]'
AND [DeletionDate] >
(SELECT TOP 1 [SynchronizationDate]
FROM [dbo].[SynchronizationLog]
ORDER BY [SynchronizationDate] DESC)
The problem occurs if I do not have synchronizations available yet, the T-SQL SELECT does not return any row while it should returns all the rows cause there are no synchronization records available.
Is there a T-SQL function like COALESCE that I can use with DateTime?
Your subquery should look like something like this:
SELECT COALESCE(MAX([SynchronizationDate]), '0001-01-01')
FROM [dbo].[SynchronizationLog]
It says: Get the last date, but if there is no record (or all values are NULL), then use the '0001-01-01' date as start date.
NOTE '0001-01-01' is for DATETIME2, if you are using the old DATETIME data type, it should be '1753-01-01'.
Also please note (from https://msdn.microsoft.com/en-us/library/ms187819(v=sql.100).aspx)
Use the time, date, datetime2 and datetimeoffset data types for new work. These types align with the SQL Standard. They are more portable. time, datetime2 and datetimeoffset provide more seconds precision. datetimeoffset provides time zone support for globally deployed applications.
EDIT
An alternative solution is to use NOT EXISTS (you have to test it if its performance is better or not):
SELECT
[Id],[RecordId],[TableName],[DeletionDate]
FROM
[DeletedRecords] DR
WHERE
[TableName] = '[dbo].[Person]'
AND NOT EXISTS (
SELECT 1
FROM [dbo].[SynchronizationLog] SL
WHERE DR.[DeletionDate] <= SL.[SynchronizationDate]
)
Using SQL Server 2008, have three tables, table a, table b and table c.
All have an ID column, but for table a and b the ID column is an identity integer, for table c the ID column is a varchar type
Currently a stored procedure take a name param, following certain logic, insert to table a or table b, get the identity, prefix with 'A' or 'B' then insert to table c.
Problem is, table C ID column potentially have the duplicated values, i.e. if identity from table A is 2, there might already have 'A2','A3','A5' in the ID column for table C, how to write a T-SQL query to identify the next available value in table C then ensure to update table A/B accordingly?
[Update]
this is the current step,
1. depends on input parameter, insert to table A or table B
2. initialize seed value = ##Identity
3. calculate ID value to insert to table C by prefix 'A' or append 'B' with the seed value
4. look for record match in table C by ID value from step 3, if didn't find any record, insert it, else increase seed value by 1 then repeat step 3
The issue being at a certain value range, there could be a huge block of value exists in table C ID, i.e. A3000 to A500000 existed now in table C ID, the database query is extemely slow if follow the existing logic. Needs to figure out a logic to smartly get the minimum available number (without the prefix)
it is hard to describe, hope this make more sense, I truly appreciate any help on this Thanks in advance!
This should do the trick. Simple self extracting example will work in SSMS. I even made it out of order just in case. You would just change your table to be where #Data is and then change Identifier field to replace 'ID'.
declare #Data Table ( Id varchar(3) );
insert into #Data values ('A5'),('A2'),('B1'),('A3'),('B2'),('A4'),('A1'),('A6');
With a as
(
Select
ID
, cast(right(Id, len(Id)-1) as int) as Pos
, left(Id, 1) as TableFrom
from #Data
)
select
TableFrom
, max(Pos) + 1 as NextNumberUp
from a
group by TableFrom
EDIT: If you want to not worry about production data you could add this last part amending what I wrote:
Select
TableFrom
, max(Pos) as LastPos
into #Temp
from a
group by TableFrom
select TableFrom, LastPos + 1
from #Temp
Regardless if this was production environment you are going to have to hit part of it at some time to get data. If the datasets are not too large and just varchar(256) or less and only 5 million rows or less you could dump that entire column from tableC to a temp table. Honestly query performance versus imports change vastly from system to system.
Following your design there shouldn't be any duplicates in Table C considering that A and B are unique.
A | B | C
1 1 A1
2 2 A2
B1
B2
I want to fetch autoincremented varchar values from SQL Server 2008 into a textbox in asp.net in pageload event.
Suppose I have a column trn_no, data type varchar. If the 1st value inserted manually in the table, like T100, then how would I get the value T101 in the textbox in pageload.
please help me.
If you want to have alphanumeric values in key then use following sql to get last inserted id +1.
SELECT 'T'
+ Cast(Max(Substring(trn_no, 2, Len(trn_no)-1) + 1 ) AS varchar(15))
FROM table
Change Varchar(15) as per possible max length