I have the following string 2014/15 passed as a parameter to my procedure and I need to increment the 4 and 5 by 1 so I end up with 2015/16.
Obviously the string is a VARCHAR so I can't use any normal arithmetic functions, nor DATEADD. The parameter must be passed in as is and I must derive a year above and a year below as well as using the parameter.
To simplify, if you feed in 2014/15 then in my SP I will need to use 2013/14, 2014/15 and 2015/16 in various parts or the SP all derived from that 1 string.
Something you can do is this:
DECLARE #date VARCHAR(MAX)
SET #date = '2014/15'
SELECT
CAST(
CAST(
SUBSTRING(#date, 0, CHARINDEX('/', #date))
AS INTEGER) + 1
AS VARCHAR(4))
+ '/'
+ RIGHT(
CAST(
CAST(
SUBSTRING(#date, 0, CHARINDEX('/', #date))
AS INTEGER) + 2
AS VARCHAR(4))
, 2)
Here is a SQLFiddle with how the code works.
The first part of the query will return the year 2014 incremented by 1.
It will then append a slash to it. Using the first date again (2014), which is extracted in the same manner, I increment it by 2. I then convert this value to a VARCHAR value so I can do string operations on it (RIGHT() function).
I then use the RIGHT() function to extract the last 2 characters, which I append to my original string.
Here, this might help you:
DECLARE #Input varchar(10)
SET #Input = '2014/15'
DECLARE #First INT, #Second INT
SET #First = SUBSTRING(#Input, 1, CHARINDEX('/', #Input) - 1)
SET #Second = SUBSTRING(#Input, CHARINDEX('/', #Input) + 1, LEN(#Input))
SELECT CONVERT(VARCHAR(10), (#First + 1)) + '/' + CONVERT(VARCHAR(10), (#Second + 1))
Basically it pulls the two components which are separated by the forward slash character / into INT variables which you can increment or decrement as needed, and then it converts those result values back to VARCHAR and puts that back together with the separator character.
The following uses the documented implicit type conversions (Ref.) to convert the substrings to integers. Note that it does not use CharIndex to locate the solidus ("/"), but assumes that the column has exactly the format you specified: four digits, solidus, two digits.
declare #Sample as Char(7) = '2014/15';
select Cast( Left( #Sample, 4 ) + 1 as Char(4) ) + '/' +
Cast( Right( #Sample, 2 ) + 1 as Char(2) );
I came up with the following but it isn't particularly elegant
SUBSTRING(#Date, 1, 3)+CAST(CAST(SUBSTRING(#Date, 4,1)AS INT)+1 AS VARCHAR)+'/'+SUBSTRING(#Date, 6, 1)+CAST(CAST(SUBSTRING(#Date, 7,1)AS INT)+1 AS VARCHAR)
Related
I have table with some strings. I would like make select with condition string = eqauls something
I Dont have any other strings....
The select returns more rows when I Have:
What is wrong?
DECLARE #C VARCHAR(2) = 'A'+SPACE(1)
DECLARE #T TABLE (id INT NOT NULL, string VARCHAR(200) NOT NULL)
INSERT INTO #T
(
id,
string
)
VALUES
( 1, 'A'), (2,'A'+SPACE(1))
SELECT * FROM #T WHERE string = #C--With space only
Returns:
id string
1 A
2 A
I know hot to make select LIKE '%.... '.
I want to know why TSQL returns more rows.
SQL 2019, MSSQL version 18.9.2
SQL Server follows the ANSI standard when it comes to comparing strings with =. Read a longer description over here: https://dba.stackexchange.com/a/10511/7656
The bottom line is, you can't check for trailing spaces with =. Use LIKE without any % instead.
Given
CREATE TABLE T (id INT NOT NULL, string VARCHAR(200) NOT NULL)
INSERT INTO T VALUES (1, 'A')
INSERT INTO T VALUES (2, 'A ')
this
SELECT id, len(string) len, datalength(string) datalength FROM T
results in
id
len
datalength
1
1
1
2
1
2
and
SELECT id FROM T WHERE string LIKE 'A '
will give you 2. See http://sqlfiddle.com/#!18/2356c9/1
You can use one of the following solutions
-- Option 1: add to the filter the condition `DATALENGTH(#C) = DATALENGTH(string)` or 'DATALENGTH(#C) < DATALENGTH(string)'
SELECT * FROM #T WHERE string = #C and DATALENGTH(#C) <= DATALENGTH(string)
-- Option 2: Use `LIKE` and add the expresion '%'
SELECT * FROM #T WHERE string like #C + '%'
The = operator ignores trailing spaces just like LEN(). The LIKE operator does not
SELECT * FROM #T WHERE string LIKE #C
You can prove this with
SELECT CASE WHEN 'A' = 'A ' THEN 'True' ELSE 'False' END -- True
SELECT CASE WHEN 'A' = ' A' THEN 'True' ELSE 'False' END -- False because of leading space
SELECT CASE WHEN 'A' LIKE 'A ' THEN 'True' ELSE 'False' END -- False
SELECT LEN(string), FROM #T -- both return 1
DECLARE #chars NCHAR(36)
SET #chars = N'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
DECLARE #result NCHAR(4)
SET #result = SUBSTRING(#chars, CAST((RAND() * LEN(#chars)) AS INT) + 1, 1)
+ SUBSTRING(#chars, CAST((RAND() * LEN(#chars)) AS INT) + 1, 1)
+ SUBSTRING(#chars, CAST((RAND() * LEN(#chars)) AS INT) + 1, 1)
+ SUBSTRING(#chars, CAST((RAND() * LEN(#chars)) AS INT) + 1, 1)
SELECT #result
i try this but it's too long Im using nodejs and posgresql
You can generate the id with your Node.js app. Do a random with Math
Math.random().toString(36).substr(2, 4) // You can change the `4` to change the length.
It will output a string like this: 92q6
In details:
Math.random() // 0.2433971674181521
Math.random().toString(36) // 0.ghlhdmdypp8bmx6r
The toString method of a number type in javascript takes an optional parameter to convert the number into a given base. If you pass two, for example, you'll see your number represented in binary. Similar to hex (base 16), base 36 uses letters to represent digits beyond 9. By converting a random number to base 36, you'll wind up with a bunch of seemingly random letters and numbers.
— Chris Baker
Since you are using nodejs, you could use a standard integer in the database, and convert it to base36 when showing it to the user. In javascript, the parameter to toString on a numer is the base:
a = 46656
b = a.toString(36) // b = "1000"
And if you want to convert it back from base36 to a number, use parseInt:
b = "1000"
c = parseInt(c, 36) // c = 46656
If you want the string to be 4 characters, generate a number between 46656 ("1000") and 1679615 ("zzzz").
I am trying to write a code where I want to read a variable (Delta), and based on that I am trying to copy the corresponding file (TESTDIR/Delta0.5_DOS_2D_TBM.data DOS.data for Delta=0.5) to the present directory.
Program Modify_variable_based_file
character(LEN=100):: command
character(LEN=10):: chDelta
real*8:: Delta
Print*,'Enter Delta'
Read*,Delta
write(chDelta,'(f0.1)') Delta
print*,'chDelta=',chDelta,' Delta=',Delta
command='cp TESTDIR/Delta' // trim(adjustl(chDelta)) //'_DOS_2D_TBM.data DOS.data'
call system(command)
End Program Modify_variable_based_file
However, I can see chDelta is .5 instead of 0.5 when I input Delta.
Can you suggest me the correct format? And is there an alternative where I can avoid the string conversion?
Note that here my files are named with number having the most significant digit on the left of the decimal, i.e. if it Delta is 1.5, file is Delta1.5_DOS_2D_TBM.data. Zero arises before the decimal only when there are no other significant digits.
If you need only one digit after the decimal point, you can use f20.1 etc such that
character(LEN=100) :: chDelta !! use a sufficiently large buffer
write( chDelta,'(f20.1)' ) Delta
chDelta = adjustL( chDelta )
Then the chDelta corresponding to Delta=0.5 becomes "0.5" (note that adjustL() removes all the blanks before 0). Similarly, you can retain 4 digits by using the format
write( chDelta,'(f20.4)' ) Delta
which gives chDelta = "0.5000". To obtain a flexible number of nonzero digits after the decimal point, we may need to remove unnecessary zeros manually. This can be done, for example, by searching for the last nonzero digit and removing the trailing zeros.
real*8 x( 5 )
character(100) str
x(:) = [ 1.0d0, 0.2d0, 1.23d0, -123.456d0, 123.678901d0 ]
do i = 1, 5
write( str, "(f20.4)" ) x(i)
call truncate( str, 4 )
print *, "file", trim(str), ".dat"
enddo
...
subroutine truncate( str, dmax )
implicit none
character(*), intent(inout) :: str
integer, intent(in) :: dmax !! maximum number of nonzero digits
integer :: dot, k, last
str = adjustL( str )
dot = index( str, '.' )
do k = dot + dmax, dot, -1
if ( str( k:k ) /= '0' ) then
last = k
exit
endif
enddo
if ( last == dot ) last = last + 1 !! retain at least one digit
str = str( 1:last )
end
Then the output becomes
file1.0.dat
file0.2.dat
file1.23.dat
file-123.456.dat
file123.6789.dat
I'm struggling to combine two expression into one so that I can remove trailing 'mm' chars of a varchar column which holds values like 3.214mm and use those chars as numeric values.
The problem I have is that there can be also null or empty string values and I can't find a way to combine both expressions below.
Example: SQLfiddle
DECLARE #string varchar(128)
SET #string = '4.123mm'
SELECT ISNULL(NULLIF(#string,''),NULL) As MyString ;
DECLARE #createNumber varchar(128)
SET #createNumber = '4.123mm'
select LEFT(#createNumber, NULLIF (LEN(#createNumber) - 2, - 1))As MyNumber
DECLARE #createNumber varchar(128)
SET #createNumber = ''
select reverse(stuff(reverse(#createNumber), 1,2, ''))
This will return null if createnumber is shorter than 2 characters.
One way to handle mm/''/null;
select cast(isnull(replace('0' + #createNumber, 'mm', ''), 0) as decimal(6,3))
I want to split string into words like below, the output of all the string should be same:
INPUT:
1. This is a string
2. This is a string
3. This is a string
4. This is a string
OUTPUT:
This is a
Means, that I want first three words from the sentence, irrespective of the spaces.
Try this:
declare #s1 varchar(3000) ;
declare #xml xml,#str varchar(100),#delimiter varchar(10), #out varchar(max);;
select #delimiter =' '
select #s1 = 'This is a string';
select #s1 = 'This is a string ';
select #s1 = 'This is a string ';
select #s1 = 'This is a string';
select #xml = cast(('<X>'+replace(#s1,#delimiter ,'</X><X>')+'</X>') as xml)
select top 3 #out =
COALESCE(#out + ' ', '') + C.value('.', 'varchar(100)')
from #xml.nodes('X') as X(C)
where LEN(C.value('.', 'varchar(10)')) > 0
select #out
Now your case contains two steps:
1. Removing additional spaces and converting them to single space. You can use REPLACE() method to this.
SELECT REPLACE(REPLACE(REPLACE("This is a string",' ','<>'),'><',''),'<>',' ')
Process:
The innermost REPLACE changes all blanks to a less-than greater-than pair.
If there are three spaces between This and is, the innermost REPLACE returns This<><><>is.
The middle REPLACE changes all greater-than less-than pairs to the empty string, which removes them.
The<><><>is becomes The<>is.
The outer REPLACE changes all less-than greater-than pairs to a single blank. The<>is becomes
The is.
Now all the sentences are normalized with one space.
2. Split the words and get the three words.
There are lot of Stackoverflow question which discusses them. I liked the Common Table Expression to split the string : How do I split a string so I can access item x?
Let me know if you require any help in the splitting the words.
Create a Tally Table:
SELECT TOP 11000
IDENTITY( INT,1,1 ) AS Num
INTO dbo.Tally
FROM Master.dbo.SysColumns sc1,
Master.dbo.SysColumns sc2
GO
Create a Table Valued Function:
CREATE FUNCTION dbo.[fnSetSplit]
(
#String VARCHAR(8000),
#Delimiter CHAR(1)
)
RETURNS TABLE
AS
RETURN
( SELECT Num,
SUBSTRING(#String, CASE Num
WHEN 1 THEN 1
ELSE Num + 1
END,
CASE CHARINDEX(#Delimiter, #String,
Num + 1)
WHEN 0
THEN LEN(#String) - Num + 1
ELSE CHARINDEX(#Delimiter,
#String, Num + 1)
- Num
- CASE WHEN Num > 1 THEN 1
ELSE 0
END
END) AS String
FROM dbo.Tally
WHERE Num <= LEN(#String)
AND ( SUBSTRING(#String, Num, 1) = #Delimiter
OR Num = 1 )
)
Query function:
SELECT TOP 3
fss.String
FROM dbo.fnSetSplit('This is a string', ' ') fss
WHERE NOT ( fss.String = '' )
If you need to reconcatenate, look at string concatenation using FOR XML (PATH)
SQL Server 2016 (compatibility level 130) allows to use STRING_SPLIT function:
DECLARE #delimiter varchar(10) = ' '
SELECT STRING_AGG(value, #delimiter)
FROM (SELECT TOP 3 value FROM STRING_SPLIT('This is a string', #delimiter) WHERE LEN(value)>0) inq
SELECT STRING_AGG(value, #delimiter)
FROM (SELECT TOP 3 value FROM STRING_SPLIT('This is a string ', #delimiter) WHERE LEN(value)>0) inq
SELECT STRING_AGG(value, #delimiter)
FROM (SELECT TOP 3 value FROM STRING_SPLIT('This is a string', #delimiter) WHERE LEN(value)>0) inq
SELECT STRING_AGG(value, #delimiter)
FROM (SELECT TOP 3 value FROM STRING_SPLIT('This is a string', #delimiter) WHERE LEN(value)>0) inq
Result:
This is a
This is a
This is a
This is a