Currently I have a package that loads a table. However, I am wanting to change the productnumber field to a bigint that is currently a varchar. I also want to create a new column for the old productnumbers. so currently it looks like this:
ProductNumber: 1827493849, PN19379247
As you can see the product number has nonnumeric in them which is why I want a column to store the old numbers such as they are currently. but my goal is to create a column that will store these two numbers and more where it takes the leading PN off. Can someone please give examples to how this is done. Currently I have created a new table with ProductNumber as bigint and OldNumer as varchar and the table is empty. I want it to be able to store the account numbers as is under OldNumber and then insert them into the other column taking the leading PN off. Which the PN must be taken off before inserting to the ProductNumber column because it is a bigint. Help is greatly appreciated.
I wouldn't recommend a bigint for this. Instead, use a numeric of the appropriate length.
If you want to convert a string by removing the first two characters, you can use stuff():
select try_convert(numeric(20), stuff(productnumber, 1, 2, ''))
If you don't know where the number begins, then look for it using patindex():
select try_convert(numeric(20), stuff(productnumber, 1, patindex('%[0-9]%', productnumber) - 1, ''))
Related
I'm developing a database with SQL Server 2012 SP2.
I have a table with a NVARCHAR(20) column, and it will have numbers: "000001", "000002", etc.
I need to get the greatest value in that column and convert it to int. How can I do it?
I have found that I can convert a nvarchar to int with this sql sentence:
SELECT CAST(YourVarcharCol AS INT) FROM Table
But I don't know how can I get the max value in that column because the numbers are nvarchar.
UPDATE:
By the way, this column is NVARCHAR because I need to store text on it. I'm testing my solution and I need to store ONLY numbers to test it.
If your numbers are padded like in the example given and all have the same width, you can just sort them alphanumerically and then cast the max-value to INT or BIGINT (depending on your numbers range).
If there are very many rows it was much faster, especially if there is an index on this column...
Something like
SELECT TOP 1 * FROM YourTable
ORDER BY NumberColumn DESC
or, if you need the max-value only:
SELECT MAX(NumberColumn) FROM YourTable
If you have to deal with negative numbers or differently padded numbers you have to cast them first
SELECT TOP 1 * FROM YourTable
ORDER BY CAST(NumberColumn AS INT) DESC
or
SELECT MAX(CAST(NumberColumn AS INT)) FROM YourTable
Please note:
If you've got very many rows, the second might get rather slow. Read about sargable
If your NumberColumn might include invalid values, you have to check, Read about ISNUMERIC().
The best solution - in any case - was to use an indexed numeric column to store these values
Try this one...
I think MAX is enough.
SELECT max(CAST(YourVarcharCol AS INT)) FROM Table
Try this
SELECT MAX(t.Y) from (SELECT CAST(YourVarcharCol AS INT) as Y FROM Table) t
You should try this on finding the highest value:
SELECT MAX(CAST(YourVarcharCol AS INT)) AS FROM Table
If all the data follow the same padding and formatting pattern, a simple max(col) would do.
However, if not, you have to cast the values to int first. Searching on a columns cast to some other datatype will not use an index, if there's any, but will scan the whole table instead. It may or may not be OK for you, depending on requirements and number of rows in the table. If performance is what you need, then create a calculated column as try_cast( col as int), and create an index on it.
Note that you should not use cast, but try_cast instead, to guard against values that can't be cast (if you use a datatype to store something which is essencially of another datatype, it always opens up a possibility for errors).
Of couse, if you can change the original column's type to int, it would be the best.
This will return max int value
SELECT MAX(IIF(ISNUMERIC(YourVarcharCol) = 1, YourVarcharCol, '0') * 1) FROM Table
You can use like this
select max(cast(ColumnName AS INT ))from TableName
I have a column in a table which consists of data like name50, somename20, other40, some65 like that.
I want to split the text part and number part and add the number part into another table with an empty column, which contains a column already with the text part. Now I have add the number part to the corresponding name part in this table.
For example in the second table I have a column called Textpart with the same text part from the first tables column (which I want to split) with all the names repeated several times randomly. And another caolumn called Numberpart which is empty.
Now I have to fill that numberpart with the corresponding numbers from the first table.
Please help me. thank you.
You can use a combination of substring and patindex.
First extract the numeric part. To get the text part just replace the previously found numeric part with an empty string.
select substring(data, patindex('%[0-9]%', data), len(data)) as numeric_part,
replace(data, substring(data, patindex('%[0-9]%', data), len(data)), '') as text_part
from tablename
To update the other table with the numeric part, use the text_part column to join.
Note that this will only work well if the numbers are towards the end.
How do I alter a sql varchar column to a decimal column when there are nulls in the data?
I thought:
ALTER TABLE table1
ALTER COLUMN data decimal(19,6)
But I just get an error, I assume because of the nulls:
Error converting data type varchar to numeric. The statement has been terminated.
So I thought to remove the nulls I could just set them to zero:
ALTER TABLE table1
ALTER COLUMN data decimal(19,6) NOT NULL DEFAULT 0
but I dont seem to have the correct syntax.
Whats the best way to convert this column?
edit
People have suggested it's not the nulls that are causing me the problem, but non-numeric data. Is there an easy way to find the non-numeric data and either disregard it, or highlight it so I can correct it.
If it were just the presence of NULLs, I would just opt for doing this before the alter column:
update table1 set data = '0' where data is null
That would ensure all nulls are gone and you could successfully convert.
However, I wouldn't be too certain of your assumption. It seems to me that your new column is perfectly capable of handling NULL values since you haven't specified not null for it.
What I'd be looking for is values that aren't NULL but also aren't something you could turn in to a real numeric value, such as what you get if you do:
insert into table1 (data) values ('paxdiablo is good-looking')
though some may argue that should be treated a 0, a false-y value :-)
The presence of non-NULL, non-numeric data seems far more likely to be causing your specific issue here.
As to how to solve that, you're going to need a where clause that can recognise whether a varchar column is a valid numeric value and, if not, change it to '0' or NULL, depending on your needs.
I'm not sure if SQL Server has regex support but, if so, that'd be the first avenue I'd investigate.
Alternatively, provided you understand the limitations (a), you could use isnumeric() with something like:
update table1 set data = NULL where isnumeric(data) = 0
This will force all non-numeric values to NULL before you try to convert the column type.
And, please, for the love of whatever deities you believe in, back up your data before attempting any of these operations.
If none of those above solutions work, it may be worth adding a brand new column and populating bit by bit. In other words set it to NULL to start with, and then find a series of updates that will copy data to this new column.
Once you're happy that all data has been copied, you should then have a series of updates you can run in a single transaction if you want to do the conversion in one fell swoop. Drop the new column and then do the whole lot in a single operation:
create new column;
perform all updates to copy data;
drop old column;
rename new column to old name.
(a) From the linked page:
ISNUMERIC returns 1 for some characters that are not numbers, such as plus (+), minus (-), and valid currency symbols such as the dollar sign ($).
Possible solution:
CREATE TABLE test
(
data VARCHAR(100)
)
GO
INSERT INTO test VALUES ('19.01');
INSERT INTO test VALUES ('23.41');
ALTER TABLE test ADD data_new decimal(19,6)
GO
UPDATE test SET data_new = CAST(data AS decimal(19,6));
ALTER TABLE test DROP COLUMN data
GO
EXEC sp_RENAME 'test.data_new' , 'data', 'COLUMN'
As people have said, that error doesn't come from nulls, it comes from varchar values that can't be converted to decimal. Most typical reason for this I've found (after checking that the column doesn't contain any logically false values, like non-digit characters or double comma values) is when your varchar values use comma for decimal pointer, as opposed to period.
For instance, if you run the following:
DECLARE #T VARCHAR(256)
SET #T = '5,6'
SELECT #T, CAST(#T AS DEC(32,2))
You will get an error.
Instead:
DECLARE #T VARCHAR(256)
SET #T = '5,6'
-- Let's change the comma to a period
SELECT #T = REPLACE(#T,',','.')
SELECT #T, CAST(#T AS DEC(32,2)) -- Now it works!
Should be easy enough to look if your column has these cases, and run the appropriate update before your ALTER COLUMN, if this is the cause.
You could also just use a similar idea and make a regex search on the column for all values that don't match digit / digit+'.'+digit criteria, but i suck with regex so someone else can help with that. :)
Also, the american system uses weird separators like the number '123100.5', which would appear as '123,100.5', so in those cases you might want to just replace the commas with empty strings and try then?
I am having following values in database table :
12.00
15.00
18.00
20.00
I want to remove all decimal ZEROS from all values , So how can I do this using SQL query. I tried replace query but that is not working.
I want values like :
12
15
18
20
My replace query :
select height(replace (12.00, '')) from table;
Please help.
Since all your values end with ".00", there will be no rounding issues, this will work
SELECT CAST(columnname AS INT) AS columnname from tablename
to update
UPDATE tablename
SET columnname = CAST(columnname AS INT)
WHERE .....
Here column name must be decimal.
select CAST(columnname AS decimal(38,0)) from table
Simply update with a convert/cast to INT:
UPDATE YOUR_TABLE
SET YOUR_COLUMN = CAST(YOUR_COLUMN AS INT)
WHERE -- some condition is met if required
Or convert:
UPDATE YOUR_TABLE
SET YOUR_COLUMN = CONVERT(INT, YOUR_COLUMN)
WHERE -- some condition is met if required
To test you can do this:
SELECT YOUR_COLUMN AS CurrentValue,
CAST(YOUR_COLUMN AS INT) AS NewValue
FROM YOUR_TABLE
As I understand your question, You have one table with column as datatype decimal(18,9).
And the column contains the data as follows:-
12.00
15.00
18.00
20.00
Now if you want to show record on UI without decimal value means like (12,15,18,20) then there are two options:-
Either cast this column as int in Select Clause
or may be you want to update this column value like (12,15,18,20).
To apply, First very simple just use the cast in select clause
select CAST(count AS INT) from tablename;
But if you want to update your column data with int value then you have to update you column datatype
and to do that
ALTER TABLE tablename ALTER COLUMN columnname decimal(9,0)
Then execute this
UPDATE tablename
SET count = CAST(columnname AS INT)
First of all, you tried to replace the entire 12.00 with '', which isn't going to give your desired results.
Second you are trying to do replace directly on a decimal. Replace must be performed on a string, so you have to CAST.
There are many ways to get your desired results, but this replace would have worked (assuming your column name is "height":
REPLACE(CAST(height as varchar(31)),'.00','')
EDIT:
This script works:
DECLARE #Height decimal(6,2);
SET #Height = 12.00;
SELECT #Height, REPLACE(CAST(#Height AS varchar(31)),'.00','');
If it's a decimal data type and you know it will never contain decimal places you can consider setting the scale property to 0. For example to decimal(18, 0). This will save you from replacing the ".00" characters and the query will be faster. In such case, don't forget to to check if the "prevent saving option" is disabled (SSMS menu "Tools>Options>Designers>Table and database designer>prevent saving changes that require table re-creation").
Othewise, you of course remove it using SQL query:
select replace(cast([height] as varchar), '.00', '') from table
Your data type is DECIMAL with decimal places, say DECIMAL(10,2). The values in your database are 12, 15, 18, and 20.
12 is the same as 12.0 and 12.00 and 12.000 . It is up to the tool you are using to select the data with, how to display the numbers. Yours either defaults to two digits for decimals or it takes the places from your data definition.
If you only want integers in your column, then change its data type to INT. It makes no sense to use DECIMAL then.
If you want integers and decimals in that column then stay with the DECIMAL type. If you don't like the way you are shown the values, then format them in your application. It's up to that client program to decide for instance if to display point or comma for the decimal separator. (The database can be used from different locations.)
Also don't rely on any database or session settings like a decimal separator being a point and not a comma and then use REPLACE on it. That can work for one person and not for the other.
You can use the floor function.
Example:
Select FLOOR(${selectedColumn}) from ${tableName}
I have a voucher format stored which reads something like this:
[VOUTYPECODE][ISBIRTHDAY][ISREUSABLE][STARTD][ENDD]VT555 + (RunningNo)
Referring to the query portion below,
#VouFormatLastNum is a string format represented like this:
'VouT001012012010420120704VT555181' derived by querying the respective [] bracketed items from the voucher format as seen above. Now, I am using 'VT555' as a blocker which is stored in #VouFormatCore (derived by detaching all bracketed items) to retrieve the running no. of the previous issued voucher which is '181' so that I can add a +1 to that running no. for my next voucher.
Everything works fine until I change my voucher format's with a different blocker other than VT555. Apparently, the last voucher will still have VT555 but the new #VouFormatCore has been changed to some other value hence I can no longer perform the query below to retrieve the running no.
I have been trying to think of ways to get by this problem. Anyway care to share a solution? Thanks.
--#VouFormatLastNum = 'VouT001012012010420120704VT555181' (This is obtained by querying the Top 1 voucher from the voucher table ordered by issue date.)
Declare #position as int
Set #position = (select len(#VouFormatLastNum) - charindex(reverse(#VouFormatCore),reverse(#VouFormatLastNum)) +1)
--#VouFormatLastNum will now contain the next running no. after selecting the substring below:
Set #VouFormatLastNum = (select substring(#VouFormatLastNum, #position+1,len(#VouFormatLastNum)-#position) + 1)
select #VouFormatLastNum
Set #NextVoucher= #var1 + #var2 + #var3 + #var4 + #var5 + #VouFormatCore + #VouFormatLastNum
Are you able to change the storage mechanism?
As you have 6 or 7 pieces of information, you should ideally have 6 or 7 fields in your storage table. The final string can then be reconstituted from those fields, whilst also making querying individual elements very simple...
I'll assume MS SQL Server from your example...
CREATE TABLE vouchers (
id INT IDENTITY(1,1),
VouTypeCode NCHAR(7) NOT NULL,
IsBirthday NCHAR(2) NOT NULL,
IsReusable NCHAR(2) NOT NULL,
StartD SMALLDATETIME NOT NULL,
EndD SMALLDATETIME NOT NULL,
PRIMARY KEY (id)
)
Now, to create a new voucher, just insert into the table, except for the id field, and a new id will be created for you. And you can create the whole voucher code from that record.
You can also, as necessary, change the data types to e more flexible/appropriate to their actual use. And add additional fields, such as a 'Blocker' field to allow different vouchers to have different blockers.
If you can't change the data structure, you need to be specific about the constraints on the data-format of the voucher codes. For example, I see you use REVERSE(), so can I assume that 'VT555' may sometimes appear earlier in the string? Will the running number always be a set length, or have a max/min length?
Without knowing the exact constraints it's not possible to write an algorithm that deals with multiple different blockers.
Options could be...
Check for other blockers if 'VT555' never appears CHARINDEX() = 0
Check for other blockers if CHARINDEX() > 8 (or some other value), as it appears to early in the string to count.
Scan the reversed string for the first non-numeric character. The alpha and numeric characters surrounding that point form the blocker. Iterate though all blockers until an appropriate match is found.
To be more specific in the answer, however, you need to be more specific about the problem space. Sorry.