Why is "0D0" considered numeric in SQL Server 2008? - sql

Any idea why ISNUMERIC('0D0') = 1 is TRUE in SQL Server 2008?
I'm validating ID numbers from another system, which sometimes contain letters that we don't want to bring over, but this combination is tripping up the code (the specific ID that it thinks is numeric is "005406257D6"). Downstream we're doing CONVERT(BIGINT, #val), which is obviously choking when it finds these "D" values.
What special case am I hitting, and how do I account for it?

Basically, IsNumeric is useless - all it verifies is that the string can be converted to any of the numeric types. In this case, "0D0" can be converted to a float. (I can't remember the reason, but effectively "D" is a synonym for "E", and means it's scientific notation):
select CONVERT(float,'2D3')
2000
If you want to verify that it's just digits, then not #val like '%[^0-9]%' would be a better test. You can improve this further by adding a length check also.

An good explanation of why.
http://www.sqlservercentral.com/articles/IsNumeric/71512/
(below is #RedFilter's more exhaustive query/list)
SELECT [Ascii Code] = STR(Number)
,[Ascii Character] = CHAR(Number)
,[ISNUMERIC Returns] = ISNUMERIC(CHAR(Number))
FROM Master.dbo.spt_Values
WHERE Type = 'P'
AND Number BETWEEN 0 AND 255
AND ISNUMERIC(CHAR(Number)) = 1
UNION
SELECT [Ascii Code] = STR(Number)
,[Ascii Character] = CHAR(Number)
,[ISNUMERIC Returns] = ISNUMERIC('0' + CHAR(Number) + '0')
FROM Master.dbo.spt_Values
WHERE Type = 'P'
AND Number BETWEEN 0 AND 255
AND ISNUMERIC('0' + CHAR(Number) + '0') = 1
yeilds
Ascii Code Ascii Character
---------- ---------------
0
9
10
11
12
13
36 $
43 +
44 ,
45 -
46 .
48 0
49 1
50 2
51 3
52 4
53 5
54 6
55 7
56 8
57 9
68 D
69 E
92 \
100 d
101 e
128 €
160  
162 ¢
163 £
164 ¤
165 ¥

Related

Make all combinations two digit from single string

I have a Textbox1.Text like that: 1784397425
How can I get the 2 combinations or 1 combination out of here?
this is a model:
Like 17 78 84 43 39 97 74 42 25 1 7 8 4 3 9 7 4 2 5
That's another model:
It can also be like this: (first digit 1, we take 1 by 7, then 1 by 8 and so on.)
17 18 14 13 19 17 14 15
and so on...
78 74 73 79 77 74 72 75
84 83 89 87 84 82 85
43 49 47 44 42 45
39 37 34 32 35
and so on...
any such model algorithm would help me a lot either of these two.
Code 3: unfortunately this doesn't work very well.
Since they're strings to begin with you can use.
Left(str,n) n is the number of left characters you want.
Right(str,n) n is the number of Right characters you want.
Mid(str,n,nn) Mid is like substring where n is the starting char, and nn is the number from start you want from the str.
Dim line1 = "47"
Dim d1 As String = Left(line1,1) 'this is 4
Dim d2 As String = Right(line1,1) 'this is 7
now the math
Dim a1 As Integer = Int(d1) + Int(d2)
or
Dim a1 As Integer = CInt(d1) + CInt(d2)
As suggested by Andrew, use Substring to extract the portion of the string that you want.
I've wrapped that in an iterator that returns all the substrings:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TextBox2.Text = String.Join(" ", Substrings(TextBox1.Text, 2))
End Sub
Public Iterator Function Substrings(ByVal source As String, ByVal length As Integer) As IEnumerable(Of String)
If length >= 1 AndAlso length <= source.Length Then
For i As Integer = 0 To (source.Length - length)
Yield source.Substring(i, length)
Next
End If
End Function
If you want the user to set the value of the length parameter, then drop a NumericUpDown control on your form and grab the .Value from that.

Two Condition Where-clause SQL

I need to filter some rows when 2 conditions are met, but not excluding the other rows.
Table:
idRow idMaster idList
1 10 45
2 10 46
3 10 47
4 11 10
5 11 98
6 14 56
7 16 28
8 20 55
Example:
When:
idMaster=10 and id List=45 (only show this combination for idMaster 10)
idMaster=11 and idList=98 (only show this combination for idMaster 11)
list all other rows as well.
Expected result:
idRow idMaster idList
1 10 45
5 11 98
6 14 56
7 16 28
8 20 55
Running SQL Server 2014
I tried combinations of CASE IF but all cases only filter the idMaster=10,11 and idList=45,98, excluding the other rows
Although you didn't mentioned the database name, this following query logic will be applicable for all databases-
SELECT *
FROM your_table
WHERE idMaster NOT IN (10,11)
OR (idMaster = 10 AND idList = 45)
OR (idMaster = 11 AND idList = 98)
You can indeed do this with a (nested) case. Hopefully this helps you understand better.
case idMaster
when 10 then case idList when 45 then 1 end
when 11 then case idList when 98 then 1 end
else 1
end = 1
This might be the best though:
not (idList = 10 and idList <> 45 or idList = 11 and idList <> 98)
Overall it's usually beneficial to avoid repeating that list of values in multiple places. Both of these avoid the need to keep things in sync when changes come.

how to split a string to multiply each single number by a value in ms access 2007

I need to split a string of 20 digits individually and multiply each single one by a value.
String (this string is in a text box) example: 11604999123400002586
After the split, I must do the following operation:
51 x 1º digit +
73 x 2º digit +
17 x 3º digit +
89 x 4º digit +
38 x 5º digit +
62 x 6º digit +
45 x 7º digit +
53 x 8º digit +
15 x 9º digit +
50 x 10º digit +
5 x 11º digit +
49 x 12º digit +
34 x 13º digit +
81 x 14º digit +
76 x 15º digit +
27 x 16º digit +
90 x 17º digit +
9 x 18º digit +
30 x 19º digit +
3 x 20º digit
In this example:
Result = 51x1 + 73x1 + 17x6 + 89x0 + 38x4 + 62x9 +
45x9 + 53x9 + 15x1 + 50x2 + 5x3 + 49x4 + 34x0 + 81x0 + 76x0 + 27x0 + 90x2
+ 9x5 + 30x8 + 3x6 = 2627
What would be the best way to do it?
In VBA you can do something like this:
Dim a(20) as Integer
a(1) = 51
a(2) = 73
…
a(20) = 3
Dim Result AS Long: Result = 0
For i = 1 to 20
Result = Result + CInt(Mid(MyString,i,1)) * a(i)
Next i
You can do it with SQL.
Create a table, say with name weights, with 2 columns:
id: Number
weight: Number
and insert these rows:
id weight
1 51
2 73
3 17
4 89
5 38
6 62
7 45
8 53
9 15
10 50
11 5
12 49
13 34
14 81
15 76
16 27
17 90
18 9
19 30
20 3
Then execute this query:
SELECT SUM(w.weight * val(mid('11604999123400002586', w.id, 1))) AS result
FROM weights AS w
Result:
2627
Consistency of structure is critical in string manipulation. Assume there will always be 20 digits in string and every record will have value.
Calculate 20 columns and add them together for the Total - here are 2:
SELECT Quotes.*, Mid([Data],1,1)*53 AS A, Mid([Data],2,1)*71 AS B, [A]+[B] AS Total FROM Quotes;
Could pull weight factor from table. DLookup is one way but domain aggregate can cause slow performance in large dataset so if weight factors will never change, probably don't want this:
SELECT Quotes.Data, Mid([Data],1,1)* DLookup("Weight","Factors","ID=1") AS A, Mid([Data],2,1)* DLookup("Weight","Factors","ID=2") AS B, [A]+[B] AS Total FROM Quotes;
A Cartesian relationship with aggregate calcs query using data and weight factors tables can calculate Total - Cartesian can also perform slowly with large dataset:
SELECT Quotes.ID, Sum(Mid([Data],[Factors].[ID],1)*[Weight]) AS Total
FROM Factors, Quotes
GROUP BY Quotes.ID;
A custom VBA function could return just the total. Call this function from query or textbox. The weight factors can be pulled from table or hard coded in an array construct.
Function GetTotal(strD) As Long
Dim rs As DAO.Recordset, x As Integer
Set rs = CurrentDb.OpenRecordset("SELECT Weight FROM Factors ORDER BY ID")
For x = 1 To 20
GetTotal = GetTotal + Mid(strD, x, 1) * rs!Weight
rs.MoveNext
Next
End Function

Replace '-' but not negative numbers in pandas

In a DataFrame, I have negative numbers, and also missing values that are given by a - . I want to replace the missing values with an empty cell, but this operation should NOT remove the - in front of the negative numbers.
It looks like:
45 45 45 45 45 45 45 45 45 45
45 45 15 31 43 45 45 45 45 45
44.24 121.55 1.80 0.00% - 97.63 -4.87 -6.02 -20.14 169.19
1 1 7 12 3 1 1 1 1 1
So the missing value cell with the - should be empty, but the -4.87 should stay intact.
Any help would be greatly appreciated.
The problem should have been addressed at the time of loading the file into the DataFrame (by providing the na_values parameter to read_csv() or whatever function you used).
At this point, use operation replace(): it replaces whole words, not individual characters.
df = df.replace("-", np.nan)

sum of differencies of rows

I have example values in column like this:
values
-------
89
65
56
78
74
73
45
23
5
654
643
543
345
255
233
109
43
23
2
The values are rising up and then fall down to 0 and rising up again.
I need to count differencies between rows in new column and the sum of these differencies too (cumulative sum) for all values. The values 56 and 5 are new differencies from zero
The sum is 819.
Example from bottom> (23-2)+(43-23)+(109-43)+..+(654-643)+(5)+(23-5)+..
Okay, here is my try. However, you need to add an Identity field (which I called "AddSequence") that starts with 1 for the first value ("2") and increments by one for every other value.
SELECT SUM(C.Diff) FROM
(
SELECT CASE WHEN (A.[Value] - (SELECT [Value] FROM [TestValue] AS B WHERE B.[AddSequence]= A.[AddSequence]-1)) > 0
THEN (A.[Value] - (SELECT [Value] FROM [TestValue] AS D WHERE D.[AddSequence]= A.[AddSequence]-1))
ELSE 0
END AS Diff
FROM [TestValue] AS A
) AS C
The first solution I had neglected that fact that we had to start over whenever the difference was negative.
I think you are looking for something like:
SELECT SUM(a - b)) as sum_of_differences
FROM ...
I think you want this for the differences, I've tested it in sqlite
SELECT CASE WHEN (v.value - val) < 0 THEN 0 ELSE (v.value - val) END AS differences
FROM v,
(SELECT rowid, value AS val FROM v WHERE rowid > 1) as next_val
WHERE v.rowid = next_val.rowid - 1
as for the sums
SELECT SUM(differences) FROM
(
SELECT CASE WHEN (v.value - val) < 0 THEN 0 ELSE (v.value - val) END AS differences
FROM v,
(SELECT rowid, value AS val FROM v WHERE rowid > 1) AS next_val
WHERE v.rowid = next_val.rowid - 1
)
EDITED - BASED OFF OF YOUR QUESTION EDIT (T-SQL)
I don't know how you can do this without adding an Id.
If you ad an Id - this gives the exact output you had posted before your edit. There's probably a better way, but this is quick and dirty - for a one time shot. Using a SELF JOIN. Differences was the name of your new column originally.
UPDATE A
SET differences = CASE WHEN A.[values] > B.[Values] THEN A.[values] - B.[Values]
ELSE A.[values] END
FROM SO_TTABLE A
JOIN SO_TTABLE B ON A.ID = (B.ID - 1)
OUTPUT
Select [Values], differences FROM SO_TTABLE
[values] differences
------------------------
89 24
65 9
56 56
78 4
74 1
73 28
45 22
23 18
5 5
654 11
643 100
543 198
345 90
255 22
233 124
109 66
43 20
23 21
2 0