Comparing double values in mysql not seems to be working properly - mysql

When I compare a float value in where clause it does not give proper results.
for example
SELECT * FROM users WHERE score = 0.61
in this query score is a column of double type
but the above query works if I check the score to be 0.50 nothing else is being searched while I have records with 0.61 too
The above query also work if i use
SELECT * FROM users WHERE trim(score) = 0.61

I suggest you to use decimal instead of float. And it also have 2 decimal places only.
Here is the documentation on how to use it. Link.
I hope this will solve your problem.

If you didn't did not specify the decimal range in your float column i will not work without casting or trim:
this works fine :
-- drop table test_float;
create table test_float(f float(6,4) , d DECIMAL(4,2));
insert into test_float values (0.5,0.5);
insert into test_float values (0.61,0.61);
select * from test_float where f = d;
select * from test_float where f = 0.61;
this don't work :
drop table test_float;
create table test_float(f float , d DECIMAL(4,2));
insert into test_float values (0.5,0.5);
insert into test_float values (0.61,0.61);
select * from test_float;
select * from test_float where f = d;
select * from test_float where f = 0.61;
select * from test_float where CAST(f as DECIMAL(16,2)) = 0.61;
it work for decimal range range = 1
why , I really don't know why ?!!

Related

SQL Joining two tables but overwriting the first if it exists in the second

I can't get this query to work the way I want it to. I have two tables with almost identical data but want one to override the other if it exists. An example would be easier than trying to explain:
There is an unadjusted balance table:
and a separate table for adjustments for each balance
the desired output takes unadjusted balances and applies any existing adjustments on top of it (if is_current=1)... essentially replacing the row but still keeping the original unadjusted current_balance.
the desired output would be something like this:
here is my current query that is not working how I want... it is flipping values and missing current_balance. i've been trying this for hours and can't get anywhere:
SELECT
*
FROM
(
SELECT
balance_adjustments.name,
balance_adjustments.user_id,
balance_adjustments.amount_owed,
balance_adjustments.when_to_pay,
balance_adjustments.current_balance
FROM
balance_adjustments
WHERE
balance_adjustments.when_to_pay = '2018-11-05'
AND balance_adjustments.is_current = true
UNION ALL
SELECT
unadjusted_balance.name,
unadjusted_balance.user_id,
unadjusted_balance.amount_owed,
unadjusted_balance.when_to_pay,
unadjusted_balance.current_balance
FROM
unadjusted_balance
LEFT OUTER JOIN balance_adjustments ON balance_adjustments.user_id = unadjusted_balance.user_id
AND balance_adjustments.name = unadjusted_balance.name
AND balance_adjustments.when_to_pay = unadjusted_balance.when_to_pay
AND balance_adjustments.is_current = true
WHERE
unadjusted_balance.when_to_pay = '2018-11-05'
AND balance_adjustments.name IS NULL
) AS table1
some additional commands to help anyone set this scenario up to test:
CREATE TABLE balance_adjustments
(
name varchar(30),
user_id varchar(30),
amount_owed float,
when_to_pay datetime,
current_balance float,
is_current boolean
);
CREATE TABLE unadjusted_balance
(
name varchar(30),
user_id varchar(30),
amount_owed float,
when_to_pay datetime,
current_balance float
);
insert into balance_adjustments values ('ricardo', '82340001', 100.00, '2018-11-05', null, 1)
insert into balance_adjustments values ('ricardo', '82340001', 33.00, '2018-11-05', null, 0)
insert into unadjusted_balance values ('joseph', '82340000', 2400.00, '2018-11-05', 4049.00)
insert into unadjusted_balance values ('ricardo', '82340001', 899.00, '2018-11-05', 500.00)
thanks for any help
If you just want to replace the amount_owed by the value from the balance_adjustments table where is_current is 1 (and I am assuming there is only one of these values), then a simple LEFT JOIN and COALESCE will suffice. The COALESCE ensures any NULL values from unmatched rows in the balance_adjustments table get replaced by the original value from the unadjusted_balances table. It's not clear from your question whether you want to replace the when_to_pay field as well, I have assumed you have in this query. If you don't, just replace COALESCE(ba.when_to_pay, ub.when_to_pay) AS when_to_pay with ub.when_to_pay.
SELECT ub.name, ub.user_id,
COALESCE(ba.amount_owed, ub.amount_owed) AS amount_owed,
COALESCE(ba.when_to_pay, ub.when_to_pay) AS when_to_pay,
ub.current_balance
FROM unadjusted_balance ub
LEFT JOIN balance_adjustments ba ON ba.user_id = ub.user_id AND ba.is_current
ORDER BY ub.name
Output:
name user_id amount_owed when_to_pay current_balance
joseph 82340000 2400 2018-11-05 00:00:00 4049
ricardo 82340001 100 2018-11-05 00:00:00 500
Demo on dbfiddle
If you want to overwrite the unadjusted balance with balance adjustments then do do the following:
Select all unadjusted balances.
Left Join to adjustments so you can get any adjustments, making sure to filter out those who have is_current = 1.
Use the sum of amount_owed in adjustments to get the overwrite amount.
In order to default to the original if there is no adjustments, use coalesce outside of the sum, and have the original amount as the second parameter.
Coalesce will return the first value if it is not null, or the value of the next parameter otherwise. The result of the sum aggregate will be null if no rows are returned from the left join.
Query
SELECT ub.name
, ub.user_id
, COALESCE(SUM(ba.amount_owed), ub.amount_owed) AS amount_owed
, ub.when_to_pay
, ub.current_balance
FROM #unadjusted_balance AS ub
LEFT JOIN #balance_adjustments AS ba ON ba.user_id = ub.user_id AND ba.is_current = 1
GROUP BY ub.name, ub.user_id, ub.amount_owed, ub.when_to_pay, ub.current_balance;
I wasn't quite sure if you could have more than one adjustment where is_current is equal to 1. If there is at most going to be one row, then omit the aggregate and group by and just pass ba.amount_owed as the first parameter in the coalesce.

Enabling Duplicates in WHERE … IN?

I want to use a simple query to decrement a value in a table like so:
UPDATE `Table`
SET `foo` = `foo` - 1
WHERE `bar` IN (1, 2, 3, 4, 5)
This works great in examples such as the above, where the IN list contains only unique values, so each matching row has its foo column decremented by 1.
The problem is when the list contains duplicates, for example:
UPDATE `Table`
SET `foo` = `foo` - 1
WHERE `bar` IN (1, 3, 3, 3, 5)
In this case I would like the row where bar is 3 to be decremented three times (or by three), and 1 and 5 to be decremented by 1.
Is there a way to change the behaviour, or an alternative query that I can use where I can get the desired behaviour?
I'm specifically using MySQL 5.7, in case there are any MySQL specific workarounds that are helpful.
Update: I'm building the query in a scripting language, so feel free to provide solutions that perform any additional processing prior to running the query (perhaps as pseudo code, to be as useful to as many as possible?). I don't mind doing it this way, I just want to keep the query as simple as possible while giving the expected result.
If you can process your original list first to get the counts, you could dynamically construct this kind of query:
UPDATE `Table`
SET `foo` = `foo` - CASE `bar` WHEN 1 THEN 1 WHEN 3 THEN 3 WHEN 5 THEN 1 ELSE 0 END
WHERE `bar` IN (1, 3, 5)
;
Note: the ELSE is just being thorough/paranoid; the WHERE should prevent it from ever getting that far.
There is an example might be beneficial for your purpose:
create table #temp (value int)
create table #mainTable (id int, mainValue int)
insert into #temp (value) values (1),(3),(3),(3),(4)
insert into #mainTable values (1,5),(2,5),(3,5),(4,5)
select value,count(*) as AddValue
into #otherTemp
from #temp t
group by value
update m
set mainValue = m.mainValue+ ot.AddValue
from #otherTemp ot
inner join #mainTable m on m.id=ot.value
select * from #mainTable
This is a little tricky, but you can do it by aggregating first:
update table t join
(select bar, count(*) as factor
from (select 1 as bar union all select 3 as bar union all select 3 as bar union all select 3 as bar union all select 5
) b
) b
on t.bar = b.bar
t.foo = t.foo - bar.factor;

MySql calculation in aggregate

I have created this working statement for calculating "C" by using the formula C=A/B*1000000.
This works as expected and the C column is calculated correctly:
Select chemicals.Region As Region,
chemicals.Totalt As `A`,
`area`.`m2` As `B`,
((chemicals.Totalt / `area`.`m2`) * 1000000) As C
From (chemicals Join `area` On chemicals.branch = `area`.branch)
Now I need to use the same formula in an aggregated report, so I tried this:
Select chemicals.Region As Region,
sum(chemicals.Totalt) As `A`,
sum(`area`.`m2`) As `B`,
sum( ((chemicals.Totalt / `area`.`m2`) * 1000000)) As C
From (chemicals Join `area` On chemicals.branch = `area`.branch) GROUP BY Region
But then the value of "C" is not calculated correctly.
I am sure there is a way to get this right, but simply adding a sum sum function to the "C" calculation was not correct. (The columns A and B are correct, by the way).
Thanks for all help!
As figured out in the comments, the following solution will work:
((sum(chemicals.TotalT) / sum(area.m2)) * 1000000) as C

MySql IN clauses, trying to match IN list of tuples

I am trying to select duplicate records based on a match of three columns. The list of triples could be very long (1000), so I would like to make it concise.
When I have a list of size 10 (known duplicates) it only matches 2 (seemingly random ones) and misses the other 8. I expected 10 records to return, but only saw 2.
I've narrowed it down to this problem:
This returns one record. Expecting 2:
select *
from ali
where (accountOid, dt, x) in
(
(64, '2014-03-01', 10000.0),
(64, '2014-04-23', -122.91)
)
Returns two records, as expected:
select *
from ali
where (accountOid, dt, x) in ( (64, '2014-03-01', 10000.0) )
or (accountOid, dt, x) in ( (64, '2014-04-23', -122.91) )
Any ideas why the first query only returns one record?
I'd suggest you don't use IN() for this, instead use a where exists query, e.g.:
CREATE TABLE inlist
(`id` int, `accountOid` int, `dt` datetime, `x` decimal(18,4))
;
INSERT INTO inlist
(`id`, `accountOid`, `dt`, `x`)
VALUES
(1, 64, '2014-03-01 00:00:00', 10000.0),
(2, 64, '2014-04-23 00:00:00', -122.91)
;
select *
from ali
where exists ( select null
from inlist
where ali.accountOid = inlist.accountOid
and ali.dt = inlist.dt
and ali.x = inlist.x
)
;
I was able to reproduce a problem (compare http://sqlfiddle.com/#!2/7d2658/6 to http://sqlfiddle.com/#!2/fe851/1 both MySQL 5.5.3) where if the x column was numeric and the value negative it was NOT matched using IN() but was matched when either numeric or decimal using a table and where exists.
Perhaps not a conclusive test but personally I wouldn't have used IN() for this anyway.
Why are you not determining the duplicates this way?
select
accountOid
, dt
, x
from ali
group by
accountOid
, dt
, x
having
count(*) > 1
Then use that as a derived table within the where exists condition:
select *
from ali
where exists (
select null
from (
select
accountOid
, dt
, x
from ali
group by
accountOid
, dt
, x
having
count(*) > 1
) as inlist
where ali.accountOid = inlist.accountOid
and ali.dt = inlist.dt
and ali.x = inlist.x
)
see http://sqlfiddle.com/#!2/ede292/1 for the query immediately above

MySQL Insert from another table with 2 option WHERE statement

I have done my research but can not figure out how to do this. It is super simple to insert from another table but I want to include WHERE statements.
I want to insert value of a single column, column_Q from table A into table B's column_Q WHERE table A's column_W = '100' and column_Q does not already exist in table B.
I tried:
INSERT INTO B (column_Q) select DISTINCT(column_Q)
from A WHERE column_W = 100 AND b.column_Q<>a.column_Q;
Where am I doing wrong?
PS. Both tables already contain values. No field is Null.
INSERT
INTO b (q)
SELECT DISTINCT q
FROM a
WHERE a.w = 100
AND a.q NOT IN
(
SELECT q
FROM b
)
If your b.q has a UNIQUE constraint defined on it, then just use:
INSERT
IGNORE
INTO b (q)
SELECT q
FROM a
WHERE w = 100
You cannot refer to the left side of the "assignment", because there is no current row from B to compare to (that would be the one you are inserting) You need to check if a similar row is already present in B, like in:
INSERT INTO B (column_Q)
SELECT DISTINCT(A.column_Q)
FROM A
WHERE A.column_W = 100
AND NOT EXISTS (
SELECT *
FROM B
WHERE B.column_Q = A.column_Q
);