Add Column in Table with conditional in block WHERE - mysql

I was doing a query with MySQL to save all objects returned, but I'd like identify these objects based in statements of the block WHERE, that is, if determined object to satisfy the specific characteristic I'd like create one column and in this column I assignment the value 0 or 1 in the row corresponding the object if it satisfy or not satisfy these characteristic.
This is my script:
SELECT
s.id, al.ID, al.j, al.k, al.r, gal.i
FROM
datas as al
WHERE
AND s.id = al.ID
AND al.j between 1 and 1
AND al.k BETWEEN 15 and 16
AND al.r BETWEEN 67 and 72
The script above is working perfectly and I can to save all objects which it return.
So, I'd like to know if is there a way add in the query above, on block WHERE, the following statement,
( Flags & (dbo.environment('cool') +
dbo.environment('ok') -
dbo.environment('source')) ) = 25
and ((al_pp x al_pp1)-0.5/3=11
and determined the objects that satisfy or not these condition with 0 or 1 in a new column created in Table saved.
I read some tutorials about this and saw some attempts with IF, CASE, ADD COLUMN or WHEN, but none of these solved.
Thanks in advance

MySQL has if function, see here
So you can simply use it in your query:
SELECT IF(( Flags & (dbo.fPhotoFlags('SATURATED') +
dbo.fPhotoFlags('BRIGHT') +
dbo.fPhotoFlags('EDGE')) ) = 0
and petroRad_r < 18
and ((colc_u - colc_g) - (psfMag_u - psfMag_g)) < -0.4
, 1 --// VALUE IF TRUE
, 0 --// VALUE IF FALSE
) as conditional_column, ... rest of your query

Related

Recursively running a MySQL function

I have a function in MySQL that needs to be run about 50 times (not a set value) in a query. the inputs are currently stored in an array such as
[1,2,3,4,5,6,7,8,9,10]
when executing the MySQL query individually it's working fine, please see below
column_name denotes the column it's getting the data for, in this case, it's a DOUBLE in the database
The second value in the MOD() function is the input I'm supplying MySQL from the aforementioned array
SELECT id, MOD(column_name, 4) AS mod_output
FROM table
HAVING mod_output > 10
To achieve the output I require* the following code works
SELECT id, MOD(column_name, 4) AS mod_output1, MOD(column_name, 5) AS mod_output2, MOD(column_name, 6) AS mod_output3
FROM table
HAVING mod_output1 > 10 AND mod_output2 > 10 AND mod_output3 > 10
However this obviously is extremely dirty, and when having not 3 inputs, but over 50, this will become highly inefficient.
Appart from calling over 50 individual querys, is there a better way to acchieve the same sort (see below) of output?
In escennce i need to supply MySQL with a list of values and have it run MOD() over all of them on a specified column.
The only data I need returned is the id's of the rows that match the MOD() functions output with the specified input (see value 2 of the MOD() function) where the output is less than 10
Please note, MOD() has been used as an example function, however, the final function required *should* be a drop in replacement
example table layout
id | column_name
1 | 0.234977
2 | 0.957739
3 | 2.499387
4 | 48.395777
5 | 9.943782
6 | -39.234894
7 | 23.49859
.....
(The title may be worded wrong, I'm not quite sure how else you'd explain what I'm trying to do here)
Use a join and derived table or temporary table:
SELECT n.n, t.id, MOD(t.column_name, n.n) AS mod_output
FROM table t CROSS JOIN
(SELECT 4 as n UNION ALL SELECT 5 UNION ALL SELECT 6 . . .
) n
WHERE MOD(t.column_name, n.n) > 10;
If you want the results as columns, you can use conditional aggregation afterwards.

MYSQL WHERE id = 0 it should show total result

SQLFiddle
In this fiddle example i m trying to use WHERE o.d_id = 1 or 2,3,4 etc but if i use d_id= 0 it should show the total result or we can say the where clause should not work if d_id = 0.
You can do a conditional style WHERE clause like this....
WHERE (?inputvalue = 0 OR ?inputvalue = d_id)
In this case the ?inputvalue is whatever search term you want. You'll provide it from your programming language.
edit Notice that in many queries you can specify an input value just once. For example, if all you want is WHERE d_id = 17 that's easy to specify. You just put the 17 in and you're done.
But, if you follow my suggestion you need to repeat the input value. You need WHERE (0 = 17 OR d_id = 17). That will, when you give it 17, filter your result set to find the seventeens.
And, if you give it 0, like this WHERE ( 0 = 0 OR d_id = 0 ) it will find all results, not filtering on just the zeroes. That's good because there aren't any zeros.
Probably, that's not how WHERE works. If you write a statement like WHERE id = 0, you ask your database to return just the rows where the id column is set to 0. If you want your database to return all values, you have to skip this condition completly

How to Find First Valid Row in SQL Based on Difference of Column Values

I am trying to find a reliable query which returns the first instance of an acceptable insert range.
Research:
some of the below links adress similar questions, but I could get none of them to work for me.
Find first available date, given a date range in SQL
Find closest date in SQL Server
MySQL difference between two rows of a SELECT Statement
How to find a gap in range in SQL
and more...
Objective Query Function:
InsertRange(1) = (StartRange(i) - EndRange(i-1)) > NewValue
Where InsertRange(1) is the value the query should return. In other words, this would be the first instance where the above condition is satisfied.
Table Structure:
Primary Key: StartRange
StartRange(i-1) < StartRange(i)
StartRange(i-1) + EndRange(i-1) < StartRange(i)
Example Dataset
Below is an example User table (3 columns), with a set range distribution. StartRanges are always ordered in a strictly ascending way, UserID are arbitrary strings, only the sequences of StartRange and EndRange matters:
StartRange EndRange UserID
312 6896 user0
7134 16268 user1
16877 22451 user2
23137 25142 user3
25955 28272 user4
28313 35172 user5
35593 38007 user6
38319 38495 user7
38565 45200 user8
46136 48007 user9
My current Query
I am trying to use this query at the moment:
SELECT t2.StartRange, t2.EndRange
FROM user AS t1, user AS t2
WHERE (t1.StartRange - t2.StartRange+1) > NewValue
ORDER BY t1.EndRange
LIMIT 1
Example Case
Given the table, if NewValue = 800, then the returned answer should be 23137. This means, the first available slot would be between user3 and user4 (with an actual slot size = 813):
InsertRange(1) = (StartRange(i) - EndRange(i-1)) > NewValue
InsertRange = (StartRange(6) - EndRange(5)) > NewValue
23137 = 25955 - 25142 > 800
More Comments
My query above seemed to be working for the special case where StartRanges where tightly packed (i.e. StartRange(i) = StartRange(i-1) + EndRange(i-1) + 1). This no longer works with a less tightly packed set of StartRanges
Keep in mind that SQL tables have no implicit row order. It seems fair to order your table by StartRange value, though.
We can start to solve this by writing a query to obtain each row paired with the row preceding it. In MySQL, it's hard to do this beautifully because it lacks the row numbering function.
This works (http://sqlfiddle.com/#!9/4437c0/7/0). It may have nasty performance because it generates O(n^2) intermediate rows. There's no row for user0; it can't be paired with any preceding row because there is none.
select MAX(a.StartRange) SA, MAX(a.EndRange) EA,
b.StartRange SB, b.EndRange EB , b.UserID
from user a
join user b ON a.EndRange <= b.StartRange
group by b.StartRange, b.EndRange, b.UserID
Then, you can use that as a subquery, and apply your conditions, which are
gap >= 800
first matching row (lowest StartRange value) ORDER BY SB
just one LIMIT 1
Here's the query (http://sqlfiddle.com/#!9/4437c0/11/0)
SELECT SB-EA Gap,
EA+1 Beginning_of_gap, SB-1 Ending_of_gap,
UserId UserID_after_gap
FROM (
select MAX(a.StartRange) SA, MAX(a.EndRange) EA,
b.StartRange SB, b.EndRange EB , b.UserID
from user a
join user b ON a.EndRange <= b.StartRange
group by b.StartRange, b.EndRange, b.UserID
) pairs
WHERE SB-EA >= 800
ORDER BY SB
LIMIT 1
Notice that you may actually want the smallest matching gap instead of the first matching gap. That's called best fit, rather than first fit. To get that you use ORDER BY SB-EA instead.
Edit: There is another way to use MySQL to join adjacent rows, that doesn't have the O(n^2) performance issue. It involves employing user variables to simulate a row_number() function. The query involved is a hairball (that's a technical term). It's described in the third alternative of the answer to this question. How do I pair rows together in MYSQL?

Access 2013 calculated field too complex

Apparently, calculated field is way to complex. Could anyone suggest a better way to accomplish what I'm trying to do?
Goal: The value entered in the Strength Field determines that value that appears in the calculated field. Thanks in advance for any help!
[Strength] number field
[StrMod] Calculated field
Below is the expression I tried to build to support the [StrMod] calculated field.
IIf([Strength]=1,-5,
IIf([Strength]>=2 And [Strength]<=3,-4,
IIf([Strength]>=4 And [Strength]<=5,-3,
IIf([Strength]>=6 And [Strength]<=7,-2,
IIf([Strength]>=8 And [Strength]<=9,-1,
IIf([Strength]>=10 And [Strength]<=11,0,
IIf([Strength]>=12 And [Strength]<=13,1,
IIf([Strength]>=14 And [Strength]<=15,2,
IIf([Strength]>=16 And [Strength]<=17,3,
IIf([Strength]>=18 And [Strength]<=19,4,
IIf([Strength]>=20 And [Strength]<=21,5,
IIf([Strength]>=22 And [Strength]<=23,6,
IIf([Strength]>=24 And [Strength]<=25,7,
IIf([Strength]>=26 And [Strength]<=27,8,
IIf([Strength]>=28 And [Strength]<=29,9,
IIf([Strength]=30,10,Null)
Here are a few suggestions all using a non-calculated data field type.
UPDATE QUERY w/ LOOKUP TABLE
Replace the calculated field type to regular number field for [StrMod]. Create a Strength lookup table:
StrengthValue | StrengthCategory
1 -5
2 -4
3 -4
4 -3
5 -3
6 -2
... ...
Then use this table to create the below update query to be run in the AfterUpdate and AfterInsert data macros for main table or same events in main table's form.
UPDATE maintableName INNER JOIN StrengthLookUp
ON maintableName.Strength = StrengthLookup.StrengthValue
SET maintableName.StrMod = StrengthLookUp.StrengthCategory
UPDATE QUERY w/o LOOKUP TABLE
Replace the calculated field type to regular number field for [StrMod] and simply use an update query in AfterUpdate and AfterEvent events:
UPDATE maintableName
SET maintableName.StrMod =
IIf([Strength]=1,-5,
IIf([Strength]>=2 And [Strength]<=3,-4,
IIf([Strength]>=4 And [Strength]<=5,-3,
IIf([Strength]>=6 And [Strength]<=7,-2,
IIf([Strength]>=8 And [Strength]<=9,-1,
IIf([Strength]>=10 And [Strength]<=11,0,
IIf([Strength]>=12 And [Strength]<=13,1,
IIf([Strength]>=14 And [Strength]<=15,2,
IIf([Strength]>=16 And [Strength]<=17,3,
IIf([Strength]>=18 And [Strength]<=19,4,
IIf([Strength]>=20 And [Strength]<=21,5,
IIf([Strength]>=22 And [Strength]<=23,6,
IIf([Strength]>=24 And [Strength]<=25,7,
IIf([Strength]>=26 And [Strength]<=27,8,
IIf([Strength]>=28 And [Strength]<=29,9,
IIf([Strength]=30,10,Null))))))))))))))))
VBA LOGIC
Replace the calculated field type to regular number field for [StrMod]. Then, use the SELECT CASE statement in the main table's form's AfterInsert and AfterUpdate events:
SELECT CASE Me.Strength
Case 1
Me.StrMod = -5
Case 2 To 3
Me.StrMod = -4
Case 4 To 5
Me.StrMod = -3
Case 6 To 7
Me.StrMod = -3
Case 8 To 9
Me.StrMod = -1
Case 10 To 11
Me.StrMod = 0
Case 12 To 13
Me.StrMod = 1
...
END SELECT
Strictly my preference, but I never work with calculated fields in case of database compatibility (i.e., MS Access 2007 accdb users) and upsizing scalability with programming languages (PHP, Python, VB ODBC connections) and other RDMS (SQL Server, MySQL).
I can not check but you will get the idea:
iif(strength/2 >= 15, null, -5 + INT(strength/2))
Did you want to simplify or complicate? If you want just to update your table once then you don't need any lookup tables...
update table
set StrMode = iif(strength/2 >= 15, null, -5 + INT(strength/2))
But if records are added to table from time to time you will need to run update as well.

Dynamic SQL query to populate column with values in other columns

I'm trying to write a SQL query for a data quality report that presents data quality failed values from multiple columns into one column. Please see the below example
FACT TABLE
Ac_Nm INAmt Ast Rcs
123 100 5000 NA
456 200 -200 Yes
789 -300 1000 No
DESIRED OUTPUT (POPULATE VAL COLUMN)
Ac_Nm Is_Clm Val
123 RCS NA
456 Ast -200
789 InAmt -300
How do I write a SQL query to populate the Val column? I've got the rest of the data quality report query written.
In the above example I have a fact table where data quality issues have been identified in various columns (negative values, 'NA' values where there should be a Yes/No response, etc). I'd like to know how to write a dynamic SQL query that returns that failed value from the Fact Table depending on the account number and the column name. In the first row the desired output lists the account number(123) with the issue column name (RCS) containing the value at issue, and the Val column listing the value causing the issue (NA). I just need to know how to write a SQL query to populate the Val column depending on the account num and issue column.
You could do it using case statements, assuming only one column is going to have a "bad" value, as follows:
SELECT Ac_Nm,
CASE WHEN INAmt < 0 THEN 'INAmt'
WHEN Ast < 0 THEN 'Ast'
WHEN Rcs = 'N/A' THEN 'RCS'
ELSE NULL END AS Is_Clm,
CASE WHEN INAmt < 0 THEN CONVERT(INAmt, char)
WHEN Ast < 0 THEN CONVERT(Ast, char)
WHEN Rcs = 'N/A' THEN Rcs
ELSE NULL END AS Val
FROM fact_table;
Then to filter out the NULL values, wrap the query in a subquery and select from it. If you need a hand doing that, give me a shout.