I have a MySQL table (below):
I can fetch the min or max of the column values simply but my problem is:
If any 3 or more fields value matched then fetch that value (if 3 fields values matched more than one value then the lowest of those values), for row #1 2100 will be the output and for row#3 55 will be the output.
If no field value matched with a minimum of 3 fields the lowest value of the entire row will be fetched, for row# 2 the output will be 1900.
I can use IF (e.g. select if(col1 = col2, col1, col2) from table) in select but I didn't find a solution for this situation. Can anyone help to write a MySQL query for this?
Thanks in advance!
You can use this query to get the results you want. It uses two nested subqueries: the first unpivots the data into a single column; the second then counts how many of each column value occur for a given ID value. The outer query then tests the maximum of the counts; if it is >= 3 then the minimum value which has a count of 3 or more is chosen, otherwise the minimum column value is chosen as the minimum column:
SELECT ID,
CASE WHEN MAX(cnt) >= 3 THEN MIN(CASE WHEN cnt >= 3 THEN col END)
ELSE MIN(col)
END AS min_col
FROM (
SELECT ID, col, COUNT(col) AS cnt
FROM (SELECT ID, col1 AS col FROM data
UNION ALL
SELECT ID, col2 FROM data
UNION ALL
SELECT ID, col3 FROM data
UNION ALL
SELECT ID, col4 FROM data
UNION ALL
SELECT ID, col5 FROM data
UNION ALL
SELECT ID, col6 FROM data
UNION ALL
SELECT ID, col7 FROM data
) d
GROUP BY ID, col
) dd
GROUP BY ID
Output (for your sample data):
ID min_col
1 2100
2 1900
3 55
Demo on SQLFiddle
I've been trying to pull off a fairly complex SQL query (maybe simple?) to compress a table with repetitive information. I'm using MySQL 5.7.14 in SequelPro. I'm a novice SQL user with a basic understanding of joins, unions etc. I'm thinking a subquery with some group bys is needed for this one, but I don't know how to do it best.
A simple example of what I'm trying to do is illustrated by the table below:
table
For every col_1 repeated entry, I want to compress into a single entry when the range set by col_2 and 3 (start and end of a range, respectively) overlap. For col_4 and 5, the max value among entries falling in this range should be reported. With the example above, in col_1, there are three ranges for a that overlap and I want to compress this to the min for col_1 and max for col_2 with the max for col_4 and 5. For 'b' in col_2, there are two ranges (31-50, 12-15) that do not overlap, so it would return both rows as is. For c, it would return one row with range 100-300 and values 3, 2 for col_4 and col_5, respectively. The full result desired from this example is shown below:
query output
I should add that there are 'null' values in some places that should be treated as zeros.
Does anybody have anybody know the best, and simplest way to do this?
Thank you in advance!!
Update: I've tried using the range setting query suggested but I get an error. The query is as follows:
WITH a AS (SELECT range
, lower(col_2) AS startdate
, max(upper(col_3)) OVER (ORDER BY range) AS `end`
FROM `combine`
)
, b AS (
SELECT *, lag(`end`) OVER (ORDER BY range) < `start` OR NULL AS step
FROM a
)
, c AS (
SELECT *, count(step) OVER (ORDER BY range) AS grp
FROM b
)
SELECT daterange(min(`start`), max(`end`)) AS range
FROM c
GROUP BY grp
ORDER BY 1;
The error I receive is:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'a AS (SELECT range
, lower(col_2) AS startdate
, max(upper(col_3)) OVE' at line 1
This is not trivial, but it can be done in one single query.
The hard part is combining a set of intervals into the largest possible contiguous intervals. Solutions are detailed in this post.
To get the result you are after, you now need to:
Calculate the largest possible contiguous intervals for each value in col1, using the query given in the link.
The result, based on your example values, would be:
col_1 lower_bound upper_bound
a 20 60
b 12 15
b 31 50
c 100 300
Associate one of those large intervals to each row in your_table. There can only be one such interval per row, so let's INNER JOIN:
SELECT my_table.*, large_intervals.lower_bound, large_intervals.upper_bound
FROM my_table
INNER JOIN (my_awesome_query(your_table)) large_intervals
ON large_intervals.col1 = my_table.col1
AND large_intervals.lower_bound <= my_table.col2
AND large_intervals.upper_bound >= my_table.col3
You would get:
col1 col2 col3 col4 col5 lower_bound upper_bound
a 45 50 1 0 20 60
a 50 61 6 0 20 60
a 20 45 0 5 20 60
b 31 50 0 1 31 50
b 12 15 5 0 12 15
c 100 200 3 2 100 300
c 150 300 1 2 100 300
Then it's easy, just group by col1, lower_bound, upper bound:
SELECT col1, lower_bound AS col2, upper_bound AS col3, MAX(col4) AS col4, MAX(col5) AS col5 FROM (query above) decorated_table GROUP BY col1, lower_bound, upper_bound
And you get exactly the result you're after.
To get back on the hard part: The post mentioned above exposes solutions for PostgreSQL. MySQL doesn't have range types, but the solution can be adapted. For instance, instead of lower(range), use the lower bound directly col2. The solution also makes use of window functions, namely lag and lead, but that is supported by MySQL, with the same syntax, so no problem here. Also note that they use COALESCE(upper(range), 'infinity') to guard against unbound ranges. Since your ranges are finite, you don't need to care about this, you can simply use the upper range directly, i.e. col3. Here's the adaptation:
WITH a AS (
SELECT
col2,
col3,
col2 AS lower_bound,
MAX(col3) OVER (ORDER BY col2, col3) AS upper_bound
FROM combine
)
, b AS (
SELECT *, lag(upper_bound) OVER (ORDER BY col2, col3) < lower_bound OR NULL AS step
FROM a
)
, c AS (
SELECT *, count(step) OVER (ORDER BY col2, col3) AS grp
FROM b
)
SELECT
MIN(lower_bound) AS lower_bound,
MAX(upper_bound) AS range
FROM c
GROUP BY grp
ORDER BY 1;
This works for a single group. If you want to get the ranges by col1, you can tweak it like this:
WITH a AS (
SELECT
col1,
col2,
col3,
col2 AS lower_bound,
MAX(col3) OVER (PARTITION BY col1 ORDER BY col2, col3) AS upper_bound
FROM combine
)
, b AS (
SELECT *, lag(upper_bound) OVER (PARTITION BY col1 ORDER BY col2, col3) < lower_bound OR NULL AS step
FROM a
)
, c AS (
SELECT *, count(step) OVER (PARTITION BY col1 ORDER BY col2, col3) AS grp
FROM b
)
SELECT
MIN(lower_bound) AS lower_bound,
MAX(upper_bound) AS range
FROM c
GROUP BY col1, grp
ORDER BY 1;
Combining everything, we get the following, which (tested on the example you provided), returns exactly the output you expected:
WITH a AS (
SELECT
col1,
col2,
col3,
col2 AS lower_bound,
MAX(col3) OVER (PARTITION BY col1 ORDER BY col2, col3) AS upper_bound
FROM combine
)
, b AS (
SELECT *, lag(upper_bound) OVER (PARTITION BY col1 ORDER BY col2, col3) < lower_bound OR NULL AS step
FROM a
)
, c AS (
SELECT *, count(step) OVER (PARTITION BY col1 ORDER BY col2, col3) AS grp
FROM b
)
, large_intervals AS (
SELECT
col1,
MIN(lower_bound) AS lower_bound,
MAX(upper_bound) AS upper_bound
FROM c
GROUP BY col1, grp
ORDER BY 1
)
, combine_with_large_interval AS (
SELECT
combine.*,
large_intervals.lower_bound,
large_intervals.upper_bound
FROM combine
INNER JOIN large_intervals
ON large_intervals.col1 = combine.col1
AND large_intervals.lower_bound <= combine.col2
AND large_intervals.upper_bound >= combine.col3
)
SELECT
col1,
lower_bound AS col2,
upper_bound AS col3,
MAX(col4) AS col4,
MAX(col5) AS col5
FROM combine_with_large_interval
GROUP BY col1, lower_bound, upper_bound
ORDER BY col1, col2, col3;
VoilĂ !
I have a Table containing 4 columns. I want print col1,col2,col3 like this
Col1 Col2 Col3 Col4
X Y Z 1
X Y
X Z
Y Z
Z
Can it be possible in a single query??
From your recent edit, it appears that you just want to select all four columns, but order the result set ascending by Col4:
SELECT *
FROM yourTable
ORDER BY Col4
I have 4 parameters in my report and my requirement is user should be able to select all values from the parameter list.
So I have created cascading parameters but one of it shows multiple values corresponding to other parameters
eg:
A
A
A
B
B
B
B
C
C
Ideal: A
B
C
I tried by unchecking allow multiple values in Parameter properties.
Param3-> taking values from Dataset3(Col3)
Main Dataset:
SELECT Col1, Col2, Start_Date, End_Date, Col3
FROM Table
Start_Date IS NULL OR
Start_Date >= #StartDate)
AND (End_Date <= #EndDate)
AND (Col3 IN (#Param3))
Dataset 1:
SELECT DISTINCT Col1
FROM Table
Dataset 2:
SELECT DISTINCT Col2
FROM Table
WHERE (Col1IN (#Param1))
ORDER BY Col2
Dataset 3:
SELECT DISTINCT Col1, Col2, Col3
FROM Table
WHERE
(Col1 IN (#Param1))
AND (Col2 IN (#Param2))
Any inputs/ideas/suggestions if I can get only Distinct values in my parameter list instead of repeating values?
Your problem seems Dataset 3 is returning repeated values for Col3since DISTINCT clause is applied across every column you select in the query.
This is a valid return of your dataset 3
Col1 Col2 Col3
A A E
B D E
C C E
Note every row is different but Col3 has repeated values.
To get different values in your parameter you can create an additional dataset to populate Parameter3.
SELECT DISTINCT Col3
FROM Table
WHERE
(Col1 IN (#Param1))
AND (Col2 IN (#Param2))
Let me know if this helps you.
I need an SQL statement that will derive a list of rows that are unique.
Given this set of data, I want the result to remove duplicate rows where duplicate is defined as Column1 being identical and column 2 and 3 are empty
Things:
ID Column1 Column2 Column3
1 a z 4
2 b y 7
3 b m 9
4 a
5 a
6 a z 4
Expected Result:
a, z, 4
b, y, 7
b, m, 9
a, ,
a, z, 4
Note that a, z, 4 appears twice in the result and this is correct. Rows only get merged when Column1 is the same and Column2 and Column3 are empty.
How would I construct a query to get this result?
Using the unique (and therefore non-group-able) id when it's non-null, and a group-able null when it's null should work.
select Column1, Column2, Column3
from Things
group by case when Column1 is null then null else ID end,
case when Column2 is null then null else ID end,
case when Column3 is null then null else ID end
SELECT
DISTINCT
Column1
, Column2
, Column3
FROM MyTable
should do, as would:
SELECT
Column1
, Column2
, Column3
FROM MyTable
GROUP BY 1, 2, 3
You can do union as
select column1,column2,column3 from Things
union
select column1,column2,column3 from Things
where col2 = '' and col3 = '' ;
This one should work in mysql if the empty columns contain nulls. The first part of the query returns all of the 'extra' rows, but only those extras where the columns are not null (this is the way value comparison works in mysql, at least). The second (distinct) query returns one of everything, including the null values. The net result is exactly what you were asking for:
select a.Column1, a.Column2, a.Column3
from Things a, Things b
where a.Column1 = b.Column1
and a.Column2 = b.Column2
and a.Column3 = b.Column3
and a.ID < b.ID
union all
select distinct Column1, Column2, Column3 from Things;