PHP MYSQL Compare rows when defining WHERE statement - mysql

Lets say I have these DB rows
id | storage | used | status
1 - 100 - 0 - 1
2 - 1000 - 5000 - 1
I need to compare the rows "storage" and "used"
I want to select rows WHERE status = 1 and Column"storage" > Column"used".
I tried WHERE status = '1' AND storage > used
It should report back row id #1, but it doesnt.

Well, WHERE status=1 AND storage > used is correct. If you tried it and didn't get back the row with id=1 there's something wrong with your data.
Are storage and used numeric columns? Or are they stored as a VARCHAR (or, gasp, TEXT)? If so, you won't be able to compare them quite the way you want, and will first have to convert or cast them to numeric types. It would be better to change the type to actually be numeric (i.e., INT or DECIMAL or whichever other type is appropriate).

SELECT * FROM `table` WHERE status = '1' AND storage > used
should give you the right solution, like VoteyDisciple mentioned, make sure status and used are both of numeric type.

you can use SELECT * FROMtableWHERE status = '1' AND storage > used but the data type of the storage and used must be NUMERIC not VARCHAR.
if Still you didn't get correct ans then it should be problem with your data storage structure.
Thanks!

Related

Get least 10 values in mysql query

I have a table in mysql. Table Name is constitutive_table, it contains more than 40 columns and its type is varchar, it contains more than 25000 records. I wrote the query like this to get the 10 least value. But it showing like as you have seen in the picture.
SELECT `Sequence_Name`
, `Name_of_the_Protein`
, `Brain`
FROM `constitutive_table`
where `Brain` != 0
ORDER
BY cast(Brain AS int)
LIMIT 0,10
The data in the Brain column appears to be floating point, so you should be casting to the appropriate type:
SELECT Sequence_Name, Name_of_the_Protein, Brain
FROM constitutive_table
WHERE CAST(Brain AS DECIMAL(14, 8)) <> 0
ORDER BY CAST(Brain AS DECIMAL(14, 8))
LIMIT 10
Most likely what is happening now is that the 10 values you see all have the same value when cast to integer. As a result, MySQL is using some secondary sort to generate the order you do see.
While the above query may resolve your problem, ideally you should change the Brain column to some numeric type.

Conditional WHERE statements based on parameters?

I am trying to conditionally create a WHERE clause in a stored procedure. It is to act as a filter on a boolean column and there's only two outcomes I want - either only take the true values, or take all of them (no situation where I only need the false values).
The clause I am trying to use is this -
WHERE
(#customerInactive = -1 OR `listcustomers`.`active` = 1)
with the idea either the parameter is a -1 (no filter) or we do have a filter and should do listcustomers.active = 1.
I tried being more explicit as well
WHERE
((#customerInactive = 1 AND `listcustomers`.`active` = 1) OR
(#customerInactive <> 1 AND 1=1))
The second one ends up not returning anything then. How can I fix this?
This is in a stored procedure, using MySQL 5.6.
Edit: Given that I've been told my first query should do it, but it always returns listcustomers.active = 1, is this possibly a type issue? I made customerInactive a int(11). I also just tried it as a bit(1) but I am still getting the same issue, no matter my paraemter I get the TRUE filter. Or in the case of the second query, no results.
Edit 2: I don't think this should matter but the final result is the union of multiple tables of which I am going to have to do this same sort of filtering. The whole SQL query can be seen here - https://pastebin.com/6wL4ZtnF
Considering your comments, this is the results you want depending of customerInactive and the value of listcustomers.active
#customerInactive | listcustomers.active | result
------------------+----------------------+--------
0 | 0 | 1
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0
This is a NAND (Not And) that can be written such way in SQL :
NOT (#customerInactive = 1 AND listcustomers.active = 1)
The correct answer is that I confused parameters and user defined variables. I am passing in customerInactive as a parameter to the stored procedure, so I should reference it directly by name. Using the # made it look like a User defined variable which was NOT defined, hence the constant failing of my initial equality and why the true filter was always on. Thanks everyone.

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?

MS Access Calc Field with combined fields

I have been trying to resolve this calc field issue for about 30 mins, it looks like I have the single field conditions correct in the expression such as [points] and [contrib] but the combined ([points]+[contrib]) field is not meeting the requirement that sets the field to the correct member type, so when these are added it returns some other member type as basic. Might I use the between operator with the added fields...? I tried it, but there is some compositional error. So in other words if you got 45 points it sets you to basic only named in the points field, if you have contrib of 45 you are set to basic in the calc field as expected, but if it were 50 + 50, instead it is setting to basic when it should be "better" member label. Otherwise this simple statement should seem to be correct but the computer is not reading it so when adding. It must not be recognizing the combined value for some reason and calc fields do not have a sum() func.
Focus here: (([points]+[Contrib]) >= 45 And ([points]+[Contrib]) < 100),"Basic",
IIf(([points] >=45 And [points]<100) Or ([Contrib] >=45 And [Contrib] <100) Or (([points]+[Contrib]) > = 45 And ([points]+[contrib] < 100),"Basic",
IIf(([points] >=100 And [points] <250) Or ([Contrib] >=100 And [Contrib] <250) Or ((([points]+[Contrib]) >=100) And (([points]+[Contrib])<250)),"Better",
IIf(([points] >=250 And [points]<500) Or ([Contrib] >=250 And [Contrib] <500) Or ((([points]+[Contrib]) >=250) And (([points]+[Contrib])<500)),"Great",
IIf(([points] >=500) Or ([Contrib] >=500) Or (([points]+[Contrib]) >=500),"Best","Non-member"))))
Here is a data sample from an Access 2010 table which includes a calculated field named member_type:
id points Contrib member_type
-- ------ ------- ----------
1 1 1 Non-member
2 50 1 Basic
3 200 1 Better
4 300 1 Great
5 600 1 Best
If that is what you want for your calculated field, here is the expression I used for member_type:
IIf([points]+[Contrib]>=45 And [points]+[Contrib]<100,'Basic',IIf([points]+[Contrib]>=100 And [points]+[Contrib]<250,'Better',IIf([points]+[Contrib]>=250 And [points]+[Contrib]<500,'Great',IIf([points]+[Contrib]>=500,'Best','Non-member'))))
In case I didn't get it exactly correct, here is that same expression formatted so that you can better see where you need changes:
IIf([points]+[Contrib]>=45 And [points]+[Contrib]<100,'Basic',
IIf([points]+[Contrib]>=100 And [points]+[Contrib]<250,'Better',
IIf([points]+[Contrib]>=250 And [points]+[Contrib]<500,'Great',
IIf([points]+[Contrib]>=500,'Best','Non-member'
))))
Note if either points or Contrib is Null, member_type will display "Non-member". If that is not the behavior you want, you will need a more complicated expression. Since a calculated field expression can not use Nz(), you would have to substitute something like IIf([points] Is Null,0,[points]) for every occurrence of [points] and IIf([Contrib] Is Null,0,[Contrib]) for [Contrib]
It would be simpler to prohibit Null for those fields (set their Required property to Yes) and set Default Value to zero.
The BETWEEN operator returns TRUE if the value you are testing is >= or <= the limits you have for BETWEEN.
If you are looking at 50+50 then that total = 100 and you are Between 44 and 100. That would result in an answer of "Basic". Change the range for ([points]+[Contrib]) Between 44 And 100) to be ([points]+[Contrib]) Between 44 And 99)

MySql ordering problem

Consider the situation i have a table name "test"
-------
content (varchar(30))
-------
1
abc
2
bcd
-------
if i use order by
Select * from test order by content asc
i could get result like
--------
content
--------
1
2
abc
bcd
---------
but is there any way i could get the following result using query
--------
content
--------
abc
bcd
1
2
---------
To get by the collation, you can do by testing the first character... it appears you want anything starting with a numeric to be after anything alhpa oriented... something like the ISNUMERIC() representation by Ted, but my quick check doesn't show such function in MySQL.. So an alternative... because numerics in ASCII list are less than "A" (char 65)
Select *
from test
order by
case when left( content, 1 ) < "A" then 2 else 1 end,
content
Although I've seen different CONVERT() calls, I don't have MySQL available to confirm. However, in addition to the above case/when, you can add a SECOND case/when and call some UDF() or other convert function on the "content" value. If the string starts as alpha, it should return a zero value so the first case/when will keep them to the top of the list, then since all are all non-convertible to numeric would have a value of zero... no impact on the sort, then finally the content itself which will keep in alpha order.
HOWEVER, if your second case/when / convert function call DOES return a numeric value, then it will be properly sorted within the numeric grouping segment... which will then supercede that of the content... However, if content was something like
100 smith rd and
100 main st
they will sort in the same "100" category numeric value, but then alphabetically by the content as
100 main st
100 smith rd
100
this will do it:
SELECT *
FROM test
ORDER BY CAST(field AS UNSIGNED), field ASC
select * from sometable order by content between '0' and '9', content
Not sure on MySql but on SQL Server you can do this...
SELECT * FROM test
ORDER BY IsNumeric(content), content
The order of results is defined by collation used, so if you can find the right collation then yes.
http://dev.mysql.com/doc/refman/5.0/en/charset-collate.html
//edit
This is tricky. I've done some research and it seems that no currently available collation can do that. However there's also possibility to add new collation to MySQL. Here's how.