=IF(D8="","",(IF((OR(R8<-3000,R8>3000)),"Outlier", IF((AND(S8>=-50%,S8<=50%,T8>=-50%,T8<=50%)),"Matched", IF((OR(AB8<-50%,AB8>50%)),"Outlier","Matched")))))
Assuming your column/field names are D, R, S, T and AB - from table #myTab
SELECT CASE
WHEN D = ',' AND (R < -3000 OR R > 3000) THEN 'Outlier'
WHEN D = ',' AND (S >= -50 AND S <= 50 AND T >= -50 AND T <= 50) THEN 'Matched'
WHEN D = ',' AND (AB < -50 OR AB > 50) THEN 'Outlier'
WHEN D = ',' THEN 'Matched'
ELSE NULL END
AS Result
FROM #myTab;
Note this is written with the D = ',' so that each line stands alone - in case you want to modify it.
Otherwise, you can make the first check to be WHEN D <> ',' THEN NULL then remove the later checks on D.
Related
I am working with manufacturing costs and the value of the fabrication still left to go (the "Net Work In Process"). The SQL is straight arithmetic but the query doesn't result in a value if there is a minus sign (subtraction) in the denominator. The database columns:
A = Material issued cost
B = Miscellaneous cost adds
C = Labor
D = Overhead
E = Setup cost
F = Scrap cost
G = Received cost (cost of assemblies completed already)
H = Original Quantity ordered
I = Quantity deviation
J = Quantity split from order
K = Quantity received (number of assemblies completed already)
The Net WIP cost is nothing more than the total cost remaining divided by the total quantity remaining. So in short, I'm simply trying to do this:
select (A + B + C + D + E - F - G) / (H + I - J - K) from MyTable
The subtractions work fine in the numerator but as soon as I subtract in the denominator, the query simply returns no value (blank). I've tried stuff like this:
select (A + B + C + D + E - F - G) / (H + I - (J + K)) from MyTable
select (A + B + C + D + E - F - G) / (H + I + (-J) + (-K)) from MyTable
select (A + B + C + D + E - F - G) / (H + I + (J * -1) + (K * -1)) from MyTable
None of these work. Just curious if anyone has come across this on IBM's DB2 database?
Thanks.
If you are returning "blank" in a numeric calculation, then you have a NULL value somewhere. Try using coalesce():
nullif(coalesce(H, 0) + coalesce(I, 0) - coalesce(J, 0) - coalesce(K, 0), 0)
You have nulls in one of the columns H, I, J, or K. Search for the offending rows using:
select H, I, J, K
from MyTable
where H is null
or I is null
or J is null
or K is null;
Then, you can treat those special cases according you your own logic. Typically you'll replace those nulls with zeroes or other values using COALESCE().
Thanks all for your comments. I did scour the columns for NULLs and there aren't any. There are then plenty of conditions where, let's say, the factory sets the order to 10 and completes (receives) 10 with no splits and no deviation. In that case:
H + I + J + K = 0 (+10 +0 -0 -10) = 0
and I can't divide by zero. So I have a different workaround for that and thanks for everyone's help.
I have ORA-00918 error with my code and i could not find the problem... the following code gives me this error.
ORA-00918 : column ambiguously defined
can anyone give me some advice? thanks
SELECT * FROM (
SELECT * FROM (
SELECT ROWNUM AS RNUM, A.XML_MSG_ID, A.LOGIN_ID, A.ORIGINATOR, A.RECIPIENT, A.ERROR_CODE, B.DOC_NO, B.DOC_NAME, B.ERROR_MSG
FROM XML_MANAGE_TBL A, XML_REFERENCE_TBL B
WHERE A.XML_MGS_ID = B.XML_MSG_ID
AND A.ERROR_CODE <> '00000000'
AND A.XML_MSG_ID >= '20190528' AND (SUBSTR(A.XML_MSG_ID, 1, 8)) <= '20190604' ) C, EBILL_USER D WHERE D.COMP_NUM = '1258169573' AND C.ORIGINATOR = D.ORIGINATOR )
WHERE RNUM BETWEEN CASE WHEN (1-1) != 0 THEN ((1-1)*50)+1 ELSE (1-1)*50 END
AND 1*50;
The problem is most probably in second subquery select *
SELECT * FROM (
... subquery C ...
) C, EBILL_USER D WHERE ... AND C.ORIGINATOR = D.ORIGINATOR
The table D contains the same columns as the subquery C, for sure the ORIGINATORcolumn
Simple change the second query to SELECT C.* and add only the required columns from D.
The general aproach how to troubleshoot ORA-00918 is to run the query from the innermost subquery and check that the returned column names are unique.
In your case try first, which should be fine
SELECT ROWNUM AS RNUM, A.XML_MSG_ID, A.LOGIN_ID, A.ORIGINATOR, A.RECIPIENT, A.ERROR_CODE, B.DOC_NO, B.DOC_NAME, B.ERROR_MSG
FROM XML_MANAGE_TBL A, XML_REFERENCE_TBL B
WHERE A.XML_MGS_ID = B.XML_MSG_ID
AND A.ERROR_CODE <> '00000000'
AND A.XML_MSG_ID >= '20190528' AND (SUBSTR(A.XML_MSG_ID, 1, 8)) <= '20190604'
Than run the second innermost subquery
SELECT * FROM (
SELECT ROWNUM AS RNUM, A.XML_MSG_ID, A.LOGIN_ID, A.ORIGINATOR, A.RECIPIENT, A.ERROR_CODE, B.DOC_NO, B.DOC_NAME, B.ERROR_MSG
FROM XML_MANAGE_TBL A, XML_REFERENCE_TBL B
WHERE A.XML_MGS_ID = B.XML_MSG_ID
AND A.ERROR_CODE <> '00000000'
AND A.XML_MSG_ID >= '20190528' AND (SUBSTR(A.XML_MSG_ID, 1, 8)) <= '20190604' ) C, EBILL_USER D WHERE D.COMP_NUM = '1258169573' AND C.ORIGINATOR = D.ORIGINATOR
In your IDE (e.g. SQL Developer) you will see one and more columns with a suffix _1 which is a sign of duplicated column that must be excluded (for columns from the equijoin predicate) or renamed.
you just need to remove outermost query and use C.RNUM instead of RNUM in where clause. Try with below code:
SELECT * FROM (
SELECT ROWNUM AS RNUM, A.XML_MSG_ID, A.LOGIN_ID, A.ORIGINATOR, A.RECIPIENT, A.ERROR_CODE, B.DOC_NO, B.DOC_NAME, B.ERROR_MSG
FROM XML_MANAGE_TBL A, XML_REFERENCE_TBL B
WHERE A.XML_MGS_ID = B.XML_MSG_ID
AND A.ERROR_CODE <> '00000000'
AND A.XML_MSG_ID >= '20190528' AND (SUBSTR(A.XML_MSG_ID, 1, 8)) <= '20190604' ) C, EBILL_USER D WHERE D.COMP_NUM = '1258169573' AND C.ORIGINATOR = D.ORIGINATOR
and (C.RNUM BETWEEN CASE WHEN (1-1) != 0 THEN ((1-1)*50)+1 ELSE (1-1)*50 END AND 1*50);
Step1: I have a table called XYZ which contains following integer columns:
ID A B C
1 201507 20150810 20150311
2 20150812 201509 201510
I need to write a SQL query where if any values of A, B, and C is smaller than 8 digits then I need to consider it as 8 digits by adding zeros to the right of the value for step2 (I am not allowed to update the table.). For example:
ID A B C
1 20150700 20150810 20150311
2 20150812 20150900 20151000
How to add zeros to the right of the integer values through SQL query?
Step 2: I need to find for each record A<B, B<C or not. Please let me know how to write the query. I am using PostgreSQL. Thank you.
SELECT CAST(2015 AS VARCHAR(10))+REPLICATE('0',8-LEN(2015))
SELECT 2015 *(CAST('1'+REPLICATE('0',8-len(2015)) AS INT))
You can use rpad() to add trailing zeros, then cast the result back to an integer:
select id,
rpad(a::text, 8, '0')::int,
rpad(b::text, 8, '0')::int,
rpad(c::text, 8, '0')::int
from the_table;
To avoid repeating the expressions, use a derived table:
select *
from (
select id,
rpad(a::text, 8, '0')::int as a,
rpad(b::text, 8, '0')::int as b,
rpad(c::text, 8, '0')::int as c
from the_table
) t
where a < b or b < c --<< change that to the condition you want
just try this
select
ID,
A = LEFT(cast(a as varchar(100)+'00000000',8),
b = LEFT(cast(b as varchar(100)+'00000000',8),
C = LEFT(cast(c as varchar(100)+'00000000',8)
from xyz
Try this:
select cast(left(cast(A as varchar(20)) + '00000000', 8) as int) as [A],
cast(left(cast(B as varchar(20)) + '00000000', 8) as int) as [B],
cast(left(cast(C as varchar(20)) + '00000000', 8) as int) as [C]
from TABLE_NAME
If you want to avoid any casting, this might be solution:
select case when 8 - LEN(A) > 0 then A * Power(10, (8 - LEN(A))) else A end as [A],
case when 8 - LEN(B) > 0 then B * Power(10, (8 - LEN(B))) else B end as [B],
case when 8 - LEN(C) > 0 then C * Power(10, (8 - LEN(C))) else C end as [C]
from MY_TABLE
I Come across below problem and not sure how to get it sorted:
We have a dimensions of the boxes in database:
L,W,H
As the box may be measured in random position , for example the values for Lenght may be allocated in to Height column etc.
Now , we have a band for boxes which contains two conditions regarding the dimensions:
Band:
Every Box with Maximum of 24x34x6
OR
Every Box with Maximum of 21x21x21
To calculate this by AND , OR statements will be possible but we will end up with 100's of lines of code only for first condition as the number of combinations will be 27 and then this will need to by applied in sql statement for each of the columns H,L,W.
I managed to get the total number of combinations by cross join but how to apply that to CASE statement and get reasonable performance and amount of code ?
CREATE TABLE #XMS1
( XMS1 int)
INSERT #XMS1 select 6
INSERT #XMS1 select 24
INSERT #XMS1 select 34
select
a.XMS1 as H,
b.XMS1 as L,
c.XMS1 as W
from #XMS1 as a
cross join #XMS1 b
cross join #XMS1 c
The values of L,W,H can be everyting from 0 to 100 but I need to select only the lines which fits in to the band...
Oracle:
You can use this to order the dimensions and then just filter on smallest, middle and largest:
SELECT *
FROM (
SELECT LEAST( l, w, h ) AS small,
l + w + h - LEAST( l, w, h ) - GREATEST( l, w, h ) AS middle,
GREATEST( l, w, h ) AS large
FROM your_box_dimensions_table
)
WHERE ( small <= 6 AND middle <= 24 AND large <= 36 )
OR ( small <= 21 AND middle <= 21 AND large <= 21 ) -- or more simply: large <= 21
;
SQL Server:
Since SQL Server does not appear to have a LEAST or GREATEST function, you could just write a user-defined function for LEAST and GREATEST with three inputs and then just call that to mimic the Oracle solution.
Or:
SELECT *
FROM (
SELECT CASE
WHEN l <= w AND l <= h THEN l
WHEN w <= h THEN w
ELSE h
END AS small,
CASE
WHEN w <= l AND l <= h THEN l
WHEN h <= l AND l <= w THEN l
WHEN l <= w AND w <= h THEN w
WHEN h <= w AND w <= l THEN w
ELSE h
END AS middle,
CASE
WHEN l >= w AND l >= h THEN l
WHEN w >= h THEN w
ELSE h
END AS large
FROM your_box_dimensions_table
)
WHERE ( small <= 6 AND middle <= 24 AND large <= 36 )
OR ( small <= 21 AND middle <= 21 AND large <= 21 ); -- or more simply: large <= 21
Daniel, I think #MT0 has answered this so don't mark this as an answer I'm just simply expanding his answer into a complete example.
This first step is simply building a list of values between 1 and 100 to help create the table containing box dimensions.
DECLARE #n TABLE (n int)
INSERT INTO #n
SELECT ones.n + 10*tens.n +1
FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) ones(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) tens(n)
ORDER BY 1
Now creating a physical table Boxes to store each combination of box dimensions (1 million records)
CREATE TABLE Boxes (d1 int, d2 int, d3 int)
INSERT INTO Boxes
SELECT a.n, b.n, c.n
FROM #n a
cross join #n b
cross join #n c
Now create a view over this table with three additional columns, these will hold the dimensions in size order (small medium, large) (thanks to MT0 for saving me having to type all that out!)
You could also use a physical table instead of a view but this way offers a bit more flexibility if requirements change.
CREATE VIEW BoxesExtended AS
select
*
, CASE
WHEN d1 <= d2 AND d1 <= d3 THEN d1
WHEN d2 <= d3 THEN d2
ELSE d3
END AS small
, CASE
WHEN d2 <= d1 AND d1 <= d3 THEN d1
WHEN d3 <= d1 AND d1 <= d2 THEN d1
WHEN d1 <= d2 AND d2 <= d3 THEN d2
WHEN d3 <= d2 AND d2 <= d1 THEN d2
ELSE d3
END AS middle
, CASE
WHEN d1 >= d2 AND d1 >= d3 THEN d1
WHEN d2 >= d3 THEN d2
ELSE d3
END AS large
from Boxes
Now all we have to do is query the view to get the boxes that match your criteria
SELECT *
FROM BoxesExtended
WHERE (large <=34 and middle <=24 and small <=6)
OR (large <=21 and middle <=21 and small <=21)
You could extend this by having a 'Bands' table along the lines of
BandID BandName MaxSmall MaxMiddle MaxLarge
1 BandA 6 24 36
2 BandA 21 21 21
3 BandB 30 40 50
and then join this to the BoxesExtended view. This would allow you to define bands and then query against the view to get matching boxes within each BandName
I do have a lot of strings in my database (PostgreSQL), an example:
with mystrings as (
select 'H e l l o, how are you'::varchar string union all
select 'I am fine, t h a n k you'::varchar string union all
select 'This is s t r a n g e text'::varchar string union all
select 'With c r a z y space b e t w e e n characters'::varchar string
)
select * from mystrings
Is there a way how I can remove spaces between characters in words? For my example the result should be:
Hello, how are you
I am fine, thank you
This is strange text
With crazy space between characters
I started with replace, but there are many such words with spaces between characters and I cannot even find them all.
Because it might be difficult to meaningfully concatenate characters, it might be better idea to get just list of concatenation candidates. Using example data, the result should be:
H e l l o
t h a n k
s t r a n g e
c r a z y
b e t w e e n
Such query should find and return all substrings in string when there are at least three individual characters separated by two spaces (and continue until patern [space] individual character occurs):
He l l o how are you --> llo
H e l l o how are you --> Hello
C r a z y space b e t w e e n --> {crazy, between}
As per your edited question, the below gets all the possible candidates that have a least three individual characters separated by two spaces
SELECT
data || ' --> {' || replace_candidates || '}'
FROM(
SELECT
data,
( SELECT
array_to_string( array_agg( data ),',' )
FROM (
SELECT
data,
length( data )
FROM (
SELECT
replace( data, ' ', '' ) AS data
FROM
regexp_split_to_table( data, '\S{2,}' ) AS data
) t
WHERE length( data ) > 2
) t ) AS replace_candidates
FROM
mystrings
) T
WHERE
replace_candidates IS NOT NULL
Working
Start looking at the inner most query first (the one with regexp_split_to_table)
The regexg gets all strings that have 2 characters in a sequence (not separated by a space)
regexp_split_to_table gets the inverse of the match, more on it here
Replace spaces by a empty char and filter records having a length greater than 2
The reaming are array aggregate functions to take care of formatting, as per your requirement, more of this here
Results
H e l l o how are you --> {Hello}
I am fine, t h a n k you --> {thank}
This is s t r a n g e text --> {strange}
With c r a z y space b e t w e e n characters --> {crazy,between}
SOME MORE TEST T E X T --> {TEXT}
SQLFIDDLE
Note: It considers chars which fall in as [space][char][space], but, you can modify it to suit your needs as [space][space][char][space] or [space][char][special_char][space] ...
Hope this helps ;p
You can use a resource such as online dictionary if the word exists then you dont have to remove spaces otherwise remove spaces or you can use a table where you have to put all strings that exist and then you have to check with that table.Hope you got my point.
The following finds possible concatenation candidates:
with mystrings as (
select 'H e l l o, how are you'::varchar string union all
select 'I am fine, t h a n k you'::varchar string union all
select 'This is s t r a n g e text'::varchar string union all
select 'With c r a z y space b e t w e e n characters'::varchar string
)
, u as (
select string, strpart[rn] as strpart, rn
from (
select *, generate_subscripts(strpart, 1) as rn
from (
select string, string_to_array(replace(string,',',''), ' ') as strpart
from mystrings
) x
) y
)
,w as (
select
string,strpart,rn,
case when length(strpart) = 1 then 1 else 0 end as indchar ,
case when coalesce(length(lag(strpart) over()),0) <> 1 and length(strpart) = 1 then 1 else 0 end as strstart,
case when coalesce(length(lead(strpart) over()),0) <> 1 and length(strpart) = 1 then 1 else 0 end as strend
from u
)
,x as (
select
string,rn,strpart,indchar,strstart,
sum(strstart) over (order by string, rn) as strid
from w
where indchar = 1 and not (strstart = 1 and strend = 1)
)
select string, array_to_string(array_agg(strpart),'') as candidate from x group by string, strid