I want to get the ratio of 2 field data from mysql
Example i have this data:
width height
1024 | 960
2880 | 1800
1440 | 900
I want to get the ratio of these data(example 4:3, 16:9, etc.)
so the output should be:
width height
4 | 3
8 | 5
8 | 5
Anyone can help me?
the problem is then to reduce a fraction (witdth/height) to its simplest form, in which case we can call a function to give us the Greatest Common Factor between those two numbers to divide into:
select width, height, width/gcd(width,height) wratio,
height/gcd(width,height) hratio
from wh
Function gcd:
CREATE FUNCTION gcd(x int, y int) RETURNS int DETERMINISTIC
BEGIN
DECLARE dividend int;
DECLARE divisor int;
DECLARE remainder int;
SET dividend := GREATEST(x, y);
SET remainder := LEAST(x, y);
WHILE remainder != 0 DO
SET divisor = remainder;
SET remainder = MOD(dividend, divisor);
SET dividend = divisor;
END WHILE;
RETURN divisor;
END
Note: I found the gcd function here: http://thenoyes.com/littlenoise/?p=143
tested in sqlfiddle
That works:
SELECT * , (
width / IF(height=0,1,height)
) AS ratio
FROM `my_table`
But be careful: do not divide by 0
Related
I have two table
First one is "tbl1"
ID fullName mobile
1 Aaaa 1234567890
2 Bbbb 9874563210
3 Cccc 1237894560
Second is "tbl2"
ID lalitude longtitude currentTime
2 26.90884600 75.79238500 2016-06-02 13:32:25
2 26.90884600 75.79238500 2016-06-02 13:32:25
1 26.90884600 75.79238500 2016-06-02 13:32:25
I have input ID = 2 and lalitude= 28.654490 and longtitude = 77.267117 and distance = 5 kilometer.
I would like to get the list of users who are inside 5 kilometer distance from the point lalitude(28.654490) and longtitude(77.267117) from tbl2 with join tbl1 table.
I am new to the geo based information.
I am using MySQL.
Either you use MySQL's spatial extensions and convert your lat / long columns into a POINT and use st_distance() function to calculate the distance between 2 points.
Or you calculate the distances yourself using lat / long values stored as floating point numbers. For a solution see mySQL longitude and latitude query for other rows within x mile radius topic here on SO. The accepted answer indicates how to calculate the distance in km.
here is my solution
DELIMITER ;;
CREATE PROCEDURE proc_getUsersByDistance(in _ID int, in _lat decimal(10,7), in _long decimal(10,7), in _distance int)
BEGIN
Declare _radius decimal(10,5);
Declare _lng_min decimal(10,7);
Declare _lng_max decimal(10,7);
Declare _lat_min decimal(10,7);
Declare _lat_max decimal(10,7);
set _radius=_distance*0.621371;
set _lng_min = _long - _radius/abs(cos(radians(_lat))*69);
set _lng_max = _long + _radius/abs(cos(radians(_lat))*69);
set _lat_min = _lat - (_radius/69);
set _lat_max = _lat + (_radius/69);
SELECT tbl1.*, tbl2.latitude, tbl2.longitude,tbl2.currentTime
from tbl1 INNER JOIN tbl2 on tbl1.ID=tbl2.ID
where tbl2.ID=_ID and ((tbl2.latitude between _lat_min and _lat_max) and (tbl2.longitude between _lng_min AND _lng_max))
order by tbl2.currentTime;
END
Is there a way to specify if we want to round a field value 4.485 to 4.48(half down) or to 4.49 (half up) in a sql query with MySql?
Thanks
Even if the question is years old, I had the same problem and found a different solution I'd like to share.
Here it is: using a conditional function you explicitly decide which way you want to round when the last decimal is 5.
For instance, if you want to round half up with 2 decimals:
SELECT IF ((TRUNCATE(mynumber*1000,0) mod 5) = 0,CEIL(mynumber*100)/100,ROUND(mynumber,2)) as value FROM mytable
You can use FLOOR function instead of CEIL if you want to round half down; if you want a different number of decimals, say n, you change the multiplier inside the TRUNCATE call (10^n+1) and you pass it to the ROUND function.
SELECT IF ((TRUNCATE(mynumber*([10^*n+1*]),0) mod 5) = 0,[CEIL|FLOOR](mynumber*100)/100,ROUND(mynumber,[*n*])) as value FROM mytable
Based on the official MySQL documentation there is no way to specify a rounding strategy. By default, ROUND uses the “round half up” rule for exact-value numbers.
However, I needed a function that behaves like java.math.BigDecimal with java.math.RoundingMode.HALF_DOWN mode. So the only solution that I found was to create my own function.
The code (tested in MySQL 5.7)
DELIMITER //
DROP FUNCTION IF EXISTS roundHalfDown //
CREATE FUNCTION roundHalfDown (
numberToRound DECIMAL(25,15),
roundingPrecision TINYINT(2)
)
RETURNS DECIMAL(25,15)
BEGIN
DECLARE digitPosition TINYINT (2) UNSIGNED DEFAULT 0;
DECLARE digitToRound TINYINT (2) DEFAULT -1;
DECLARE roundedNumber DECIMAL(20,6) DEFAULT 0;
SET digitPosition = INSTR(numberToRound, '.');
IF (roundingPrecision < 0) THEN
SET digitPosition = digitPosition + roundingPrecision;
ELSE
SET digitPosition = digitPosition + roundingPrecision + 1;
END IF;
IF (digitPosition > 0
AND digitPosition <= CHAR_LENGTH(numberToRound)
) THEN
SET digitToRound = CAST(
SUBSTR(
numberToRound,
digitPosition,
1
) AS UNSIGNED
);
SET digitPosition = digitPosition - 1;
END IF;
IF (digitToRound > -1) THEN
IF (digitToRound > 5) THEN
SET roundedNumber = ROUND(numberToRound, roundingPrecision);
ELSEIF (digitToRound = 5 AND CAST(
SUBSTR(
REPLACE(numberToRound, '.', ''),
digitPosition + 1
) AS UNSIGNED) > 0) THEN
SET roundedNumber = ROUND(numberToRound, roundingPrecision);
ELSE
SET roundedNumber = TRUNCATE(numberToRound, roundingPrecision);
END IF;
ELSEIF (roundingPrecision > 0) THEN
SET roundedNumber = numberToRound;
END IF;
RETURN roundedNumber;
END //
DELIMITER ;
Test Cases
SELECT roundHalfDown(1.541, 2); #1.54
SELECT roundHalfDown(1.545, 2); #1.54
SELECT roundHalfDown(1.5451, 2); #1.55
SELECT roundHalfDown(1.54500001, 2); #1.55
SELECT roundHalfDown(1.54499999, 2); #1.54
SELECT roundHalfDown(-1.545, 2); #-1.54
SELECT roundHalfDown(-1.5451, 2); #-1.55
SELECT roundHalfDown(555, 0); #555
SELECT roundHalfDown(1000999, -1); #1001000
SELECT roundHalfDown(1000999, -2); #1001000
SELECT roundHalfDown(1000999, -3); #1001000
SELECT roundHalfDown(1000999, -4); #1000000
I used this answer from another Stack Overflow question, but I changed it a bit for my specific case.
Andrea Pegoretti's answer is almost correct, however it will apply when it's a 5 or a 0 instead of just a 5.
My fix (for round down):
SELECT IF (SUBSTR(TRUNCATE(CEIL(mynumber*1000),0),-1) = 5,FLOOR(mynumber*100)/100,ROUND(mynumber, 2))) AS value FROM mytable
The accepted answer of this post offers a good solution :
MySQL - How can I always round up decimals?
i.e multiply by 10^n where n is the decimal place you want to round to then call ceil to round up or floor to round down and divide by 10^n.
You can use the CEIL (or CEILING) and the FLOOR functions to round up/round down.
For example:
CEIL(4.485 * 100) / 100 will return 4.49
FLOOR(4.485 * 100) / 100 will return 4.48
I have the same question and I try all kind of custom function to emulate the functionality of PHP with a round up and down, but after a while, I figured out that MySQL produces different results using float and doubles fields.
Here my test.
mysql> describe test_redondeo;
+----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| columna_double | double(15,3) | YES | | NULL | |
| columna_float | float(9,3) | YES | | NULL | |
| id | int(11) | NO | PRI | NULL | |
+----------------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
In fields type double, round function truncate, but in float round up.
mysql> select columna_double, columna_float, round ( columna_double, 2) as round_double, round ( columna_float, 2) as round_float from test_redondeo;
+----------------+---------------+--------------+-------------+
| columna_double | columna_float | round_double | round_float |
+----------------+---------------+--------------+-------------+
| 902.025 | 902.025 | 902.02 | 902.03 |
+----------------+---------------+--------------+-------------+
1 row in set (0.00 sec)
If you made a custom function for round a number using round() in any way, please pay attention to type of field.
Hope this test helps you.
According to Mysql docs,
For exact-value numbers, ROUND() uses the “round half up” rule
I had also a situation, where I was wondering why is Mysql rounding(1) 74,447 to 74,4. It was because it was in fact an endless long decimal, a approximate-value number, and not a exact-value number. The solution for me was, that I had to use ROUND() 3x like this: ROUND(ROUND(ROUND(value, 3), 2), 1). The first rounding makes sure that it's not a approximate-value number any more (where Mysql uses the “round to nearest even” rule), but a exact-value number, a decimal 3 number.
I have a table that contains color options for a product. The color options include a hex color code, which is used to generate the UI (HTML).
I would like to sort the rows so that the colors in the UI look like a rainbow, instead of the current order that sorts based off of the Name of the color (not very useful).
Here is what my query looks like. I get the R G B decimal values from the hex code. I just don't know how to order it.
I've looked into color difference algorithms. They seem more useful to compare 2 colors' similarity, not sort.
I'm using MySQL:
select a.*, (a.c_r + a.c_g + a.c_b) color_sum
from (
select co.customization_option_id,
co.designer_image_url,
concat(co.name, " (",cog.name, ")") name,
co.customization_option_group_id gr,
designer_hex_color,
conv(substr(designer_hex_color, 1, 2), 16, 10) c_r,
conv(substr(designer_hex_color, 3, 2), 16, 10) c_g,
conv(substr(designer_hex_color, 5, 2), 16, 10) c_b
from customization_options co
left join customization_option_groups cog
on cog.id = co.customization_option_group_id
where co.customization_id = 155
and co.customization_option_group_id
in (1,2,3,4)) a
order by ????
You want to sort hex codes by wavelength, this roughly maps onto the hue-value. Given a hexcode as a six character string: RRGGBB.
You just need to make a function that takes in a hexcode string and outputs the hue value, here's the formula from this Math.SO answer:
R' = R/255
G' = G/255
B' = B/255
Cmax = max(R', G', B')
Cmin = min(R', G', B')
Δ = Cmax - Cmin
I wanted to see if this would work, so I whipped up a sample program in Ruby, it samples 200 random colors uniformly from RGB-space, and sorts them, the output looks like a rainbow!
Here's the Ruby source:
require 'paint'
def hex_to_rgb(hex)
/(?<r>..)(?<g>..)(?<b>..)/ =~ hex
[r,g,b].map {|cs| cs.to_i(16) }
end
def rgb_to_hue(r,g,b)
# normalize r, g and b
r_ = r / 255.0
g_ = g / 255.0
b_ = b / 255.0
c_min = [r_,g_,b_].min
c_max = [r_,g_,b_].max
delta = (c_max - c_min).to_f
# compute hue
hue = 60 * ((g_ - b_)/delta % 6) if c_max == r_
hue = 60 * ((b_ - r_)/delta + 2) if c_max == g_
hue = 60 * ((r_ - g_)/delta + 4) if c_max == b_
return hue
end
# sample uniformly at random from RGB space
colors = 200.times.map { (0..255).to_a.sample(3).map { |i| i.to_s(16).rjust(2, '0')}.join }
# sort by hue
colors.sort_by { |color| rgb_to_hue(*hex_to_rgb(color)) }.each do |color|
puts Paint[color, color]
end
Note, make sure to gem install paint to get the colored text output.
Here's the output:
It should be relatively straight-forward to write this as a SQL user-defined function and ORDER BY RGB_to_HUE(hex_color_code), however, my SQL knowledge is pretty basic.
EDIT: I posted this question on dba.SE about converting the Ruby to a SQL user defined function.
This is based on the answer by #dliff. I initially edited it, but it turns out my edit was rejected saying "it should have been written as a comment or an answer". Seeing this would be too large to post as a comment, here goes.
The reason for editing (and now posting) is this: there seems to be a problem with colors like 808080 because their R, G and B channels are equal. If one needs this to sort or group colors and keep the passed grayscale/non-colors separate, that answer won't work, so I edited it.
DELIMITER $$
DROP FUNCTION IF EXISTS `hex_to_hue`$$
CREATE FUNCTION `hex_to_hue`(HEX VARCHAR(6)) RETURNS FLOAT
BEGIN
DECLARE r FLOAT;
DECLARE b FLOAT;
DECLARE g FLOAT;
DECLARE MIN FLOAT;
DECLARE MAX FLOAT;
DECLARE delta FLOAT;
DECLARE hue FLOAT;
IF(HEX = '') THEN
RETURN NULL;
END IF;
SET r = CONV(SUBSTR(HEX, 1, 2), 16, 10)/255.0;
SET g = CONV(SUBSTR(HEX, 3, 2), 16, 10)/255.0;
SET b = CONV(SUBSTR(HEX, 5, 2), 16, 10)/255.0;
SET MAX = GREATEST(r,g,b);
SET MIN = LEAST(r,g,b);
SET delta = MAX - MIN;
SET hue=
(CASE
WHEN MAX=r THEN (60 * ((g - b)/delta % 6))
WHEN MAX=g THEN (60 * ((b - r)/delta + 2))
WHEN MAX=b THEN (60 * ((r - g)/delta + 4))
ELSE NULL
END);
IF(ISNULL(hue)) THEN
SET hue=999;
END IF;
RETURN hue;
END$$
DELIMITER ;
Again, I initially wanted to edit the original answer, not post as a separate one.
If your products can have lots of color probably a good UI will require a color picker, normally those are rectangular, so not really something possible with the order by.
If the products have a manageable number of colors you have different choice, the easiest to implement is an order table, where for every possible color is defined an order position, this table can then be joined to your query, something like
SELECT ...
FROM (SELECT ...
...
...
, ci.color_order
FROM customization_options co
LEFT JOIN customization_option_groups cog
ON cog.id = co.customization_option_group_id
LEFT JOIN color_ ci
ON designer_hex_color = ci.color
WHERE ...) a
ORDER BY color_order
Another way to go is to transform the RGB color to hue and use this as the order.
There are different formula for this conversion, depending on wich order you want the primary color to have, all of them can be found on the wikipedia page for hue, I can update the answer to help you convert one of those to T-SQL, if needed.
MySQL function Hex to Hue. Based on Tobi's answer. :)
CREATE FUNCTION `hex_to_hue`(hex varchar(6)) RETURNS float
BEGIN
declare r float;
declare b float;
declare g float;
declare min float;
declare max float;
declare delta float;
declare hue float;
set r = conv(substr(hex, 1, 2), 16, 10)/255.0;
set g = conv(substr(hex, 3, 2), 16, 10)/255.0;
set b = conv(substr(hex, 5, 2), 16, 10)/255.0;
set max = greatest(r,g,b);
set min = least(r,g,b);
set delta = max - min;
set hue=
(case
when max=r then (60 * ((g - b)/delta % 6))
when max=g then (60 * ((b - r)/delta + 2))
when max=b then (60 * ((r - g)/delta + 4))
else null
end);
RETURN hue;
END
Is there a way to know in SQL Server 2008R2 if a point is at the south,east,etc...of another point?
For example, I have an origin point(lat1,lng1) and I want to know where point(lat2,lng2) is located from that origin: north, west,etc...
I'm trying to construct a wind rose graph and this might be useful to me.
I came up with a way of calculating the bearing using a fairly straightforward use of standard SQL functions. The ATAN function does most of the real work; the two CASE statements are just special case corrections. 1 is the source and 2 is the destination.
atan(([Longitude2]-[Longitude1])/(10e-10+[Latitude2]-[Latitude1]))*360/pi()/2
+case when [Latitude2]<[Latitude1] then 180 else 0 end
+case when [Longitude2]<[Longitude1] and [Latitude2]>[Latitude1] then 360 else 0 end
In order to calculate the bearing between two coordinates while using the Geography type in SQL Server 2008 R2, you can use this function:
CREATE FUNCTION [dbo].[CalculateBearing]
(
#pointA as geography
,#pointB as geography
)
RETURNS decimal(18,12)
AS
BEGIN
-- Declare the return variable
DECLARE #bearing decimal(18,12)
-- Declare the local variables
DECLARE #x decimal(18,12)
DECLARE #y decimal(18,12)
DECLARE #dLat decimal(18,12)
DECLARE #dLong decimal(18,12)
DECLARE #rLat1 decimal(18,12)
DECLARE #rLat2 decimal(18,12)
IF(#pointA.STIsEmpty() = 1 OR #pointB.STIsEmpty() = 1)
set #bearing = null
ELSE
BEGIN
-- Calculate delta between coordinates
SET #dLat = RADIANS(#pointB.Lat - #pointA.Lat)
SET #dLong = RADIANS(#pointB.Long - #pointA.Long)
-- Calculate latitude as radians
SET #rLat1 = RADIANS(#pointA.Lat)
SET #rLat2 = RADIANS(#pointB.Lat)
SET #y = SIN(#dLong)*COS(#rLat2)
SET #x = COS(#rLat1)*SIN(#rLat2)-SIN(#rLat1)*COS(#rlat2)*COS(#dLong)
IF (#x = 0 and #y = 0)
SET #bearing = null
ELSE
BEGIN
SET #bearing = CAST((DEGREES(ATN2(#y,#x)) + 360) as decimal(18,12)) % 360
END
END
-- Return the result of the function
RETURN #bearing
END
GO
And after this, you can use this function like this:
DECLARE #pointA as geography
DECLARE #pointB as geography
SET #pointA = geography::STGeomFromText('POINT(3 45)', 4326)
SET #pointB = geography::STGeomFromText('POINT(4 47)', 4326)
SELECT [dbo].[CalculateBearing](#pointA, #pointB)
UPDATE: Adding a schema
This morning I had need for this functionality to provide the range and cardinal direction to users when searching for nearby orders in our system. I came to Nicolas's answer here and it got me most of the way there. I created a second function that uses Nicolas's to get myself an abbreviated cardinal direction (N, NE, E, etc) for my UI.
Using Nicolas's bearing calculation provided here combined with values from https://en.wikipedia.org/wiki/Points_of_the_compass to determine ranges for each cardinal direction,
CREATE FUNCTION [dbo].[CalculateCardinalDirection]
(
#pointA as geography
,#pointB as geography
)
RETURNS varchar(2)
AS
BEGIN
DECLARE #bearing decimal(18,12)
-- Bearing calculation provided by http://stackoverflow.com/a/14781032/4142441
SELECT #bearing = dbo.CalculateBearing(#pointA, #pointB)
RETURN CASE WHEN #bearing BETWEEN 0 AND 22.5 THEN 'N'
WHEN #bearing BETWEEN 22.5 AND 67.5 THEN 'NE'
WHEN #bearing BETWEEN 67.5 AND 112.5 THEN 'E'
WHEN #bearing BETWEEN 112.5 AND 157.5 THEN 'SE'
WHEN #bearing BETWEEN 157.5 AND 202.5 THEN 'S'
WHEN #bearing BETWEEN 202.5 AND 247.5 THEN 'SW'
WHEN #bearing BETWEEN 247.5 AND 292.5 THEN 'W'
WHEN #bearing BETWEEN 292.5 AND 337.5 THEN 'NW'
ELSE 'N' -- Catches NULL bearings and the 337.5 to 360.0 range
END
END
GO
If the points data type are "Geometry" (Like UTM Coordinate System), you may use the following formula:
DEGREES(ATAN((X2-X1)/(Y2-Y1)))
+case when Y2<Y1 then 180 else 0 end
+case when Y2>Y1 and X2<X1 then 360 else 0 end
Here is the schema for more clarification:
X=X2-X1 and Y=Y2-Y1. A formula that gives the bearing clockwise from 0 (positive Y axis) to 360 degrees.
f(X,Y)=180-90*(1+SIGN(Y))*(1-SIGN(X^2))-45*(2+SIGN(Y))*SIGN(X)-180/PI()*SIGN(Y*X)*ATAN((ABS(Y)-ABS(X))/(ABS(Y)+ABS(X)))
postgresql have the pg_size_pretty() convenience function:
> select pg_size_pretty(100000);
pg_size_pretty
----------------
98 kB
Does MySQL have something similar ?
If not, before I make my own have anyone already made this, that they can share ?
There is no shipped function like that in MySQL.
So, I just created one : function pretty_size
https://github.com/lqez/pastebin/blob/master/mysql/pretty_size.sql
CREATE FUNCTION pretty_size( size DOUBLE )
RETURNS VARCHAR(255) DETERMINISTIC
BEGIN
DECLARE c INT DEFAULT 0;
DECLARE unit INT DEFAULT 1000;
DECLARE unitChar CHAR(6) DEFAULT 'KMGTPE';
DECLARE binaryPrefix BOOLEAN DEFAULT 1;
/* Set binaryPrefix = 1 to use binary unit & prefix */
/* See IEC 60027-2 A.2 and ISO/IEC 80000 */
IF binaryPrefix = 1 THEN
SET unit = 1024;
END IF;
WHILE size >= unit AND c < 6 DO
SET size = size / unit;
SET c = c + 1;
END WHILE;
/* Under 1K, just add 'Byte(s)' */
IF c = 0 THEN
RETURN CONCAT( size, ' B' );
END IF;
/* Modify as your taste */
RETURN CONCAT(
FORMAT( size, 2 ),
' ',
SUBSTR( unitChar, c, 1 ),
IF( binaryPrefix, 'iB', 'B' )
);
END $$
DELIMITER ;
pg_size_pretty
will give you Kb or MB or GB ,etc according to the internal code ,and you wont operate or sum this result ...
better use :
pg_relation_size :
returns the on-disk size in bytes ,so you can convert it to the format (kb,mb,gb) that you want.