how to limit a sql integer query result to <=1 - sql

how to limit an integer query result to 1. a return of 2 to be 1, a return 1 to be 1, and a return of 0.5 to be 0.5 because it is <= 1. i don't want to modify the tables, i just want to modify the results.
This is my exact query.
select ((select "V01" from sports where "UID" = '1') * 1.0 ) /
(select "V01" from master where "BALL" = 'REQUIREMENT') ;
I'm using postgres.

To limit, you'd do something like this:
select
case
when yourNumber >= 1 then 1
else yourNumber
end
...
Then you just apply this concept to your query.
As noted by Wiseguy, you could also do:
select LEAST(yourNumber, 1)
, since this is postgresql.
The first solution will work with any ANSI SQL compatible database.
Update
Applied to your query, I think (if I understood what you want correctly) it would be like this:
select LEAST(1,
((select "V01" from sports where "UID" = '1') * 1.0 ) /
(select "V01" from master where "BALL" = 'REQUIREMENT')
);

use the LEAST function , docs: http://www.postgresql.org/docs/8.3/static/functions-conditional.html. Also, check out GREATEST too
SELECT LEAST(1, <your value>)
EDIT replaced GREATEST with LEAST

try this:
select CASE
WHEN ((select V01 from sports where UID = '1') * 1.0 ) /
(select V01 from master where BALL = 'REQUIREMENT') >= 1
THEN 1
ELSE ((select V01 from sports where UID = '1') * 1.0 ) /
(select V01 from master where BALL = 'REQUIREMENT')
END;

Related

Select random sample of N rows from Oracle SQL query result

I want to reduce the number of rows exported from a query result. I have had no luck adapting the accepted solution posted on this thread.
My query looks as follows:
select
round((to_date('2019-12-31') - date_birth) / 365, 0) as age
from
personal_info a
where
exists
(
select person_id b from credit_info where credit_type = 'C' and a.person_id = b.person_id
)
;
This query returns way more rows than I need, so I was wondering if there's a way to use sample() to select a fixed number of rows (not a percentage) from however many rows result from this query.
You can sample your data by ordering randomly and then fetching first N rows.
DBMS_RANDOM.RANDOM
select round((to_date('2019-12-31') - date_birth) / 365, 0) as age
From personal_info a
where exists ( select person_id b from credit_info where credit_type = 'C' and a.person_id = b.person_id )
Order by DBMS_RANDOM.RANDOM
Fetch first 250 Rows
Edit: for oracle 11g and prior
Select * from (
select round((to_date('2019-12-31') - date_birth) / 365, 0) as age
From personal_info a
where exists ( select person_id b from credit_info where credit_type = 'C' and a.person_id = b.person_id )
Order by DBMS_RANDOM.RANDOM
)
Where rownum< 250
You can use fetch first to return a fixed number of rows. Just add:
fetch first 100 rows
to the end of your query.
If you want these sampled in some fashion, you need to explain what type of sampling you want.
If you are using 12C, you can use the row limiting clause below
select
round((to_date('2019-12-31') - date_birth) / 365, 0) as age
from
personal_info a
where
exists
(
select person_id b from credit_info where credit_type = 'C' and a.person_id = b.person_id
)
FETCH NEXT 5 ROWS ONLY;
Instead of 5, you can use any number you want.

Out of range integer: infinity

So I'm trying to work through a problem thats a bit hard to explain and I can't expose any of the data I'm working with but what Im trying to get my head around is the error below when running the query below - I've renamed some of the tables / columns for sensitivity issues but the structure should be the same
"Error from Query Engine - Out of range for integer: Infinity"
WITH accounts AS (
SELECT t.user_id
FROM table_a t
WHERE t.type like '%Something%'
),
CTE AS (
SELECT
st.x_user_id,
ad.name as client_name,
sum(case when st.score_type = 'Agility' then st.score_value else 0 end) as score,
st.obs_date,
ROW_NUMBER() OVER (PARTITION BY st.x_user_id,ad.name ORDER BY st.obs_date) AS rn
FROM client_scores st
LEFT JOIN account_details ad on ad.client_id = st.x_user_id
INNER JOIN accounts on st.x_user_id = accounts.user_id
--WHERE st.x_user_id IN (101011115,101012219)
WHERE st.obs_date >= '2020-05-18'
group by 1,2,4
)
SELECT
c1.x_user_id,
c1.client_name,
c1.score,
c1.obs_date,
CAST(COALESCE (((c1.score - c2.score) * 1.0 / c2.score) * 100, 0) AS INT) AS score_diff
FROM CTE c1
LEFT JOIN CTE c2 on c1.x_user_id = c2.x_user_id and c1.client_name = c2.client_name and c1.rn = c2.rn +2
I know the query works for sure because when I get rid of the first CTE and hard code 2 id's into a where clause i commented out it returns the data I want. But I also need it to run based on the 1st CTE which has ~5k unique id's
Here is a sample output if i try with 2 id's:
Based on the above number of row returned per id I would expect it should return 5000 * 3 rows = 150000.
What could be causing the out of range for integer error?
This line is likely your problem:
CAST(COALESCE (((c1.score - c2.score) * 1.0 / c2.score) * 100, 0) AS INT) AS score_diff
When the value of c2.score is 0, 1.0/c2.score will be infinity and will not fit into an integer type that you’re trying to cast it into.
The reason it’s working for the two users in your example is that they don’t have a 0 value for c2.score.
You might be able to fix this by changing to:
CAST(COALESCE (((c1.score - c2.score) * 1.0 / NULLIF(c2.score, 0)) * 100, 0) AS INT) AS score_diff

Optimization SQL, not in/not exists?

I have a request, please tell me how you can optimize it?
select distinct
trunc(dw.mdf_date) as mdf_date
,dw.dss_id
,dw.raid
,dw.host_type
,dw.volume_name
,dw.volume_size
,dw.prv
,listagg(dw.hba_wwn,',' on overflow truncate '...' without count) within group (order by dw.hba_wwn) as wwn
from
dss_wwn dw
where
dw.volume_name not in ('ADMIN')
and dw.volume_name not like '.%'
and dw.hba_wwn is not null
and not exists (select 1 from wwn shw where shw.wwn = dw.hba_wwn and shw.dic_type_eqp_id = 4 and rownum = 1)
and not exists (select 1 from dss_vmhdd shw where shw.wwid = dw.disk_wwn and rownum = 1)
group by
trunc(dw.mdf_date)
,dw.dss_id
,dw.raid
,dw.host_type
,dw.volume_name
,dw.volume_size
,dw.prv
This request works for 23 seconds.
And if you comment out this line, That works fast 0.2 seconds
and not exists (select 1 from wwn shw where shw.wwn = dw.hba_wwn and shw.dic_type_eqp_id = 4 and rownum = 1)
select count(*) from DSS_WWN --100000
select count(*) from WWN t --13000
UPD #Gro Thanks for your answer, really after I removed rownum=1 request fulfilled in 0.4 seconds

Sql-Filter the Select

SELECT DISTINCT x1.NUM_KANBAN_ID ID,
TO_CHAR(x1.DT_CREATE,'YYYY-MM-DD') CREATED,
x5.TXT_PLANT_CD CD,
TO_CHAR(x4.DT_FIRST_VIEWED,'YYYY-MM-DD') VIEWED,
TO_CHAR(x4.DT_DUE,'YYYY-MM-DD') DUE, x4.
TXT_SHUTTLE_NUMBER SHUTTLE,
(select count(*)
from WEDI_ASN_TO_DIMENSION t8
where t8.TXT_MATCH_CD='1'
AND t8.NUM_DIMENSION_ID=x2.NUM_DIMENSION_ID AND t8.NUM_MATCH_ID = x1.NUM_KANBAN_ID) ASN,
x1.TXT_JIT_CALL_NUM,
x2.NUM_VENDOR_ID VENDOR_ID
FROM WEDI_KANBAN x1, WEDI_DIMENSION x2, WEDI_USER_VENDORS x3, WEDI_KANBAN_TO_DIMENSION x4, WEDI_PLANT x5
WHERE x5.NUM_PLANT_ID = x2.NUM_PLANT_ID AND
x1.TXT_STATUS_CD = 'C' AND
x2.NUM_VENDOR_ID = x3.NUM_VENDOR_ID AND
x4.NUM_DIMENSION_ID = x2.NUM_DIMENSION_ID AND
x1.NUM_KANBAN_ID = x4.NUM_KANBAN_ID AND
x1.DT_CREATE < SYSDATE - 15 AND
x5.TXT_PLANT_CD LIKE '%' AND
x2.TXT_MATERIAL_NUM LIKE '%' AND
((x4.TXT_SHUTTLE_NUMBER IS NULL) OR (x4.TXT_SHUTTLE_NUMBER LIKE '%')) AND
x4.DT_DUE < SYSDATE - 10
ORDER BY VENDOR_ID
In the above query i should display the id's whose ASN is only 1 or 2 . If the ASN has like this 0,1,2 i Should not display those IDs. Generally if the id's ASN has 0 i should not display.
Pls suggest
Simplest solution is:
select *
from (your query)
where 0 not in (select ASN from (your query))
In order to not write the query twice:
with (your query) as A
select *
from a
where 0 not in (select asn from a)
or
with (your query) as A
select *
from a
where not exists (select * from a where asn = 0)
However, exists the posibility to rewrite your query to return no rows when exists an ASN equal to zero, but the query is hard to understand, and almost sure something is wrong because you need a DISTINCT clause. That's bad sign.
Add something like (ASN = 1) Or (ASN = 2) in your Where statement

Find closest numeric value in database

I need to find a select statement that will return either a record that matches my input exactly, or the closest match if an exact match is not found.
Here is my select statement so far.
SELECT * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p'
ORDER BY Area DESC
What I need to do is find the closest match to the 'Area' field, so if my input is 1.125 and the database contains 2, 1.5, 1 and .5 the query will return the record containing 1.
My SQL skills are very limited so any help would be appreciated.
get the difference between the area and your input, take absolute value so always positive, then order ascending and take the first one
SELECT TOP 1 * FROM [myTable]
WHERE Name = 'Test' and Size = 2 and PType = 'p'
ORDER BY ABS( Area - #input )
something horrible, along the lines of:
ORDER BY ABS( Area - 1.125 ) ASC LIMIT 1
Maybe?
If you have many rows that satisfy the equality predicates on Name, Size, and PType columns then you may want to include range predicates on the Area column in your query. If the Area column is indexed this could allow efficient index-based access.
The following query (written using Oracle syntax) uses one branch of a UNION ALL to find the record with minimal Area >= your target, while the other branch finds the record with maximal Area < your target. One of these two records will be the record that you are looking for. Then you can ORDER BY ABS(Area - ?input) to pick the winner out of those two candidates. Unfortunately the query is complex due to nested SELECTS that are needed to enforce the desired ROWNUM / ORDER BY precedence.
SELECT *
FROM
(SELECT * FROM
(SELECT * FROM
(SELECT * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p' AND Area >= ?target
ORDER BY Area)
WHERE ROWNUM < 2
UNION ALL
SELECT * FROM
(SELECT * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p' AND Area < ?target
ORDER BY Area DESC)
WHERE ROWNUM < 2)
ORDER BY ABS(Area - ?target))
WHERE rownum < 2
A good index for this query would be (Name, Size, PType, Area), in which case the expected query execution plan would be based on two index range scans that each returned a single row.
SELECT *
FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p'
ORDER BY ABS(Area - 1.125)
LIMIT 1
-- MarkusQ
How about ordering by the difference between your input and [Area], such as:
DECLARE #InputValue DECIMAL(7, 3)
SET #InputValue = 1.125
SELECT TOP 1 * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p'
ORDER BY ABS(#InputValue - Area)
Note that although ABS() is supported by pretty much everything, it's not technically standard (in SQL99 at least). If you must write ANSI standard SQL for some reason, you'd have to work around the problem with a CASE operator:
SELECT * FROM myTable
WHERE Name='Test' AND Size=2 AND PType='p'
ORDER BY CASE Area>1.125 WHEN 1 THEN Area-1.125 ELSE 1.125-Area END
If using MySQL
SELECT * FROM [myTable] ... ORDER BY ABS(Area - SuppliedValue) LIMIT 1