How can I find values with more than 2 decimal places? - sql

I am validating data and trying to find if there are any values in a single column (allowed_amount) with more than 2 decimal places (24.1145678, 234.444, -1234.09012).
with t1 as (
select (allowed_amount - round(allowed_amount,2)) as ck
from export_core_report_client_output
where runid = '0c7c2d34-6cc3-43b0-ae4b-4bd8f4bddfb0'
)
select min(ck) as min, max(ck) as max from t1

One option would be to use this formula:
SELECT
num,
CASE WHEN 100*num - CAST(100*num AS int) > 0 THEN 'yes' ELSE 'no' END AS field
FROM yourTable;
Demo
For example, for the value 24.1234, the above formula computes:
2412.34 - 2412 = 0.34 > 0
But for 24.12, we get:
2412 - 2412 = 0

You can use Charindex to do that, supposing the allowed_amount column is varchar or nvarchar
select len(substring(allowed_amount,charindex('.',allowed_amount)+1,len(allowed_amount))) from export_core_report_client_output
This will give you a count of decimal values after and then you can use the same statement in where clause to scrutinize like:
select len(substring(allowed_amount,charindex('.',allowed_amount)+1,len(allowed_amount))) from export_core_report_client_output
where len(substring(allowed_amount,charindex('.',allowed_amount)+1,len(allowed_amount)))> 2
any questions fire up in the comments

Related

SQL - split numeric into 2 columns?

I am trying to split some numeric keys in my table into separate columns (to help save space in SSAS, lower cardinality)
My data looks like the below..
LeadKey
1
2
3
5522
83746623
I want to split these into 2 columns... with 4 digits in each column. (where applicable, as anything 1>9999 won't have anything populated in the 2nd column)
So an example output of the above would be the below..
LeadKey Split1 Split2
1 1
2 2
35566 3556 6
5522 5522
83746623 8374 6623
How could I achieve this? I have split columns easily before using substring and a known character.. but never had to do a split like this. Does anyone have an approach to handle this?
Here is a solution in case you have the LeadKey numbers as int.
select LeadKey
,left(LeadKey, 4) Split1
,right(LeadKey, case when len(LeadKey)-4 < 0 then 0 else len(LeadKey)-4 end) Split2
from t
LeadKey
Split1
Split2
1
1
2
2
35566
3556
6
5522
5522
83746623
8374
6623
Fiddle
In this example, I used left for the Split1, and show the values past the 4th position for the Split2:
I've included a testing temporary table to hold our the testing values.
Feel free to adjust the code to work with your situation.
DECLARE #thelist TABLE
(
LeadKey int
);
INSERT INTO #thelist (LeadKey)
select 1 union all
select 2 union all
select 35566 union all
select 5522 union all
select 83746623
select cast(x1.LeadKey as varchar(19)),
Left(x1.LeadKey, 4) as 'Split1',
(case when len(x1.LeadKey) > 4 then right(x1.LeadKey, len(x1.LeadKey) - 4)
else '' end
) as 'Split2'
from #thelist as x1

Multiply within same column

I have a table that looks like the following:
label
value
student1
90
student2
88
student3
59
student4
77
I am trying to multiply two values if they meet the condition.
For example, I want to multiply values for student 1 and 3 together. Then I want to multiply the values for student 2 and 4.
For the first criteria, I tried the following code:
select
case
when
max(label) = "student1" or max(label) = "student3" then exp(SUM(log(value))) else 0 end as nominator
from four_students_table
Unfortunately, it gives me the value of 0. I have also tried to just add them together, but got 0 again. I am not sure what I am doing wrong here.
Expected output:
numerator
denominator
5,310
6,776
I case statement as shown in the example below would assist in filtering what you would like to aggregrate.
The following fiddle provides your desired results:
CREATE TABLE four_students_table (
label VARCHAR(8),
value INTEGER
);
INSERT INTO four_students_table
(label, value)
VALUES
('student1', '90'),
('student2', '88'),
('student3', '59'),
('student4', '77');
Query #1
SELECT
SUM(CASE WHEN label='student1' THEN value ELSE 0 END)*
SUM(CASE WHEN label='student3' THEN value ELSE 0 END) as nominator,
SUM(CASE WHEN label='student2' THEN value ELSE 0 END)*
SUM(CASE WHEN label='student4' THEN value ELSE 0 END) as denominator
FROM
four_students_table;
nominator
denominator
5310
6776
View on DB Fiddle
Consider below (I feel this is more inline with your intends/sample in your question)
select distinct
round(exp(sum(if(label in ('student1', 'student3'), ln(value), 0)) over())) as nominator,
round(exp(sum(if(label in ('student2', 'student4'), ln(value), 0)) over())) as denominator
from `project.dataset.four_students_table`
if applied to sample data in your question - output is

SQL Filter numbers between x and x and ignore strings

I have a table in SQL Server where I need to filter rooms by name and type. The problem is, that the names are stored as varchar and there are also some rooms with letters. I need to filter out the rooms with letters before I can compare them as int or otherwhise I will get an error.
Here's an example from Room.Name:
030
210a
210b
Lan-Room-A
240
I can work around the room names with a or b with LEFT(Rooms.Name, 3) but if I want to add (LEFT(Rooms.Name, 3) BETWEEN 0 and 350 and it gets to Lan-Room-A it oviously can't convert a string to int. I also need to do additional filtering like Room.Type = 6 for example.
SELECT
Room.Name,
Room.Descr,
Room.MainUser
WHERE
LEFT(Room.Name, 1) NOT LIKE '%[0-9]%'
AND LEFT(Room.Name, 3) BETWEEN 0 AND 350
AND Room.Type = 6
(Removed some joins for simplicity)
I simply need to filter out the rows which contain strings before the when clause, but I have no idea how.
Do you guys have any idea?
Please note that I can't edit the database.
Thanks in advance.
You could use TRY_CAST:
SELECT *
FROM Rooms
WHERE TRY_CAST(LEFT(Rooms.Name, 3) AS INT) BETWEEN 0 and 350;
DBFiddle Demo
Your second approach is not guaranteed to work even with correct check:
WHERE LEFT(Room.Name, 1) NOT LIKE '%[0-9]%'
AND LEFT(Room.Name, 3) BETWEEN 0 AND 350
and Room.Type = 6
Query optimizer could check conditions in any order so LEFT(Room.Name, 3) BETWEEN 0 AND 350 could yield conversion error.
I don't understand the issue. You can use strings:
WHERE Room.Name NOT LIKE '[0-9]%' AND
LEFT(Room.Name, 3) BETWEEN '0' AND '350' AND
Room.Type = 6
However, I suspect your intention is captured by:
WHERE Room.Name >= '000' AND
Room.Name < '351' AND
Room.Type = 6
This works because you have zero-padded the numbers, so string comparisons will work.
For 2008. Please use this.
Solution-
;WITH CTE AS
(
SELECT '030' a UNION ALL
SELECT '210a' UNION ALL
SELECT '210b' UNION ALL
SELECT 'Lan-Room-A' UNION ALL
SELECT '240'
)
SELECT * FROM CTE
WHERE
PATINDEX('%[0-9]%', a) = 1 AND
1 = CASE WHEN CAST(LEFT(a, 3) AS INT) BETWEEN 0 and 350 THEN 1 ELSE 0 END
OUTPUT
a
----------
030
210a
210b
240
(4 rows affected)

How to sort combination of integer and text in PostgreSQL?

I have this table
id value
1 OK
2 xminimum
3 NO
4 YES
I want to sort this table by value where minimum is always first then the rest according to alphabetic order of value column
Meaning:
xminimum
NO
OK
YES
I wrote this query:
Select *
from table_a
order by case when value='xminimum' then 1 else ????? end
I don't know what to put in the else... conceptually it should be else value end so it means alphabetic order.. but I can not combine integer with text.
How do I fix it?
As requested, copied from my comment:
Select *
from table_a
order by case when value='xminimum' then 1 else 2 end, value
Another solution:
SELECT *
FROM table_a
ORDER BY value <> 'xminimum', value;
Do it like you have and add the value column as second column to sort by:
SELECT *
FROM table_a
ORDER BY CASE WHEN value='xminimum' THEN 1 ELSE 2 END, value

SQL : select one column if two columns are equal, else select both

I have the following SQL select problem:
I have two columns positive threshold and negative threshold (among several other columns like name, ids.... ).
If their (absolute) value is the same (multiply by -1) then I want to select only the positive threshold as column [threshold].
If the values are different, I want to select two columns [positiveThreshold] and [negativeThreshold].
Thank you in advance.
select null as [threshold], positivethreshold, negativethreshold
from table
where negativethreshold is null
or (positivethreshold + negativethreshold) <> 0
union
select positivethreshold, null, null
from table
where (positivethreshold + negativethreshold) = 0