checking multiple values in between two columns mysql - mysql

I am trying for a MySQL query to check multiple values between two columns values.
For example, for one value here is my query which works
SELECT column3
FROM table
WHERE (12 between minvaluecol AND maxvaluecol) AND
id = 123;
I would like to check multiple values like (12,13,14,67,68) and should return the values that are in between minvaluecol and maxvaluecol columns. In this case, only 12,13,14 are in between minvaluecol and maxvaluecol columns whereas 67,68 are not.
my table looks like this,
id | minvaluecol | maxvaluecol
---- | ----------- | ------------
121 | 23 | 35
123 | 10 | 20
125 | 40 | 50
output for id 123 should look like,
12 | true
13 | true
14 | true
67 | false
68 | false
Please help me with this query in MySQL. Thank you.

Update
Completely revamped the answer based on updated question.
As you need all the values as different rows, you need to SELECT all of them with UNION and LEFT JOIN it with the original table, e.g.:
SELECT a.val, IF(a.val BETWEEN tv.minvaluecol AND maxvaluecol, 'true', 'false') AS result
FROM (
SELECT 12 AS val
UNION
SELECT 13 AS val
UNION
SELECT 14 AS val
UNION
SELECT 67 AS val
UNION
SELECT 68 AS val) a
JOIN test_values tv
WHERE tv.id = 123;
Here's the SQL Fiddle.

The easiest way to get your result is to Insert those values into a table and then join like this:
SELECT value,
CASE WHEN value between minvaluecol AND maxvaluecol THEN 'true ELSE 'false' END
FROM table
CROSS JOIN table_with_values
WHERE id = 123
ORDER BY value

Related

Get sum of repeating items as an array of IDS

I have question regarding getting sum of the items by their IDS. Is there are any elegant way to do this with sql procedure? The IDS are coming from in array, for instance (10, 10, 11, 11, 12). So the sum should be 300. If I am right functions cannot take array as an parameter in mysql, so it can be procedure.
The closest what I could think of:
SELECT price FROM table WHERE FIND_IN_SET(ID, (10, 10, 11, 11, 12))
tho it doesn't work properly.
I know that SUM is almost does what I need, except it skips duplicate values, if there is a way to use it so it wouldn't skip, then it probably would be fastest. Table is below:
|---------------------|------------------|
| ID | Price |
|---------------------|------------------|
| 10 | 34 |
|---------------------|------------------|
| 11 | 99 |
|---------------------|------------------|
| 12 | 34 |
|---------------------|------------------|
You would create a derived table and join:
select sum(t.price)
from (select 10 as id union all
select 10 as id union all
select 11 as id union all
select 11 as id union all
select 12 as id
) i join
t
on i.id = t.id;
In MySQL 8.0, you can do this with running your input array thru JSON_TABLE, which will interpret your array entries as rows.
This approach respects the array's order and doesn't skip duplicities, as it's not a filtering function like WHERE.
set #arr = '[10, 10, 11, 11, 12]';
select *
from json_table(#arr, '$[*]' columns (id int path '$')) input
left join products using (id);
-> id price
10 34
10 34
11 99
11 99
12 34
select sum(price)
from json_table(#arr, '$[*]' columns (id int path '$')) input
left join products using (id);
-> 300

Lead function for missing records

I am using below query
select id,
number_sequ,
startvalue
lead(startvalue,1,0) over (partition by id order by number_sequ) AS End_value
from mytable
to populate the following output
id number_sequ startvalue End_value
---- ----- ---------- -----------
AAA 1 30 20
AAA 2 20 10
AAA 4 10 15
AAA 5 15 0
BBB 1 12 23
BBB 3 23 34
BBB 4 34 0
But there are missing records in sequence
id number_sequ startvalue End_value
---- ----- ---------- -----------
AAA 3
BBB 2
I have tried different ways to find out missing numbers in Sequence and try to insert with 0 values. after that i can use lead function. unable to find out efficient way
INSERT INTO mytable (id, number_sequ, startvalue)
select id ,number_sequ ,'0'
from mytable
where (some condition to specify missing data)
Can any one help me to solve above issue.
You can get the missing values with the following approach: generate all possible values and then filter out the ones that exist.
select i.id, n.n, 0 as start_value
from (select id, min(number_seq) as min_ns, max(number_seq) as max_ns
from mytable
group by id
) i join
(select row_number() over (partition by number_seq) as n
from mytable
) n
on n.n <= i.max_ns left join -- just a bunch of numbers
mytable t
on t.id = i.id and
t.number_seq = n.n
where t.id is null;
You can pop the insert before the select to insert these values into your table.
Note that this generates the sequence numbers you need using the original data. So it assumes that your table has enough rows for the numbers you need.
If the missing values are always in between existing values, you can find the gaps using the Snowflake's JavaScript UDTFs
For example, here's a function that finds gaps in a sequence, and then we use it to generate "empty" rows:
create or replace table x(id int, seq int, startVal int) as select * from
values(1,1,11),(1,2,12),(1,4,14),(2,2,22),(2,5,25);
CREATE OR REPLACE FUNCTION find_gaps(SEQ float)
RETURNS TABLE (GAP float)
LANGUAGE JAVASCRIPT
AS '
{
initialize: function(argumentInfo, context) {
this.lastRow = null;
},
processRow: function (row, rowWriter, context) {
let curRow = row.SEQ;
if (this.lastRow == null || this.lastRow + 1 == curRow) {
this.lastRow = curRow;
} else {
while (this.lastRow + 1 < curRow) {
this.lastRow++;
rowWriter.writeRow({GAP: this.lastRow});
}
}
}
}'
;
select id, seq, startVal from x
union all
select id, gap, 0 from x,
table(find_gaps(seq::float)
over (partition by id order by seq));
----+-----+----------+
ID | SEQ | STARTVAL |
----+-----+----------+
1 | 1 | 11 |
1 | 2 | 12 |
1 | 4 | 14 |
2 | 2 | 22 |
2 | 5 | 25 |
2 | 3 | 0 |
2 | 4 | 0 |
1 | 3 | 0 |
----+-----+----------+
You can use variations of this function also e.g. if you know the range of your values per id, just feed it expected min/max as well. Also, you might need something special if your input contains NULL values (but then - what should be the result? :))
Apart from the suggested solutions, if you still want to stick to Lead function,
Lead function analyses data that has values, the result of it can have null values based on partition but the data it uses for analyses should have values. In my view, What you did is right to include the missing sequence in your result.
http://www.mysqltutorial.org/mysql-window-functions/mysql-lead-function/

SELECT where the first two numbers are equal

I have this in my database:
75012
75016
94400
94500
94300
78400
I would like to select only the string where only the first two numbers match and show how many 94 there are so it will output 75012 = 2, 94 = 3, 78 = 1.
Here is what I tried:
select cpostal from fiche_personne WHERE cpostal LIKE LEFT(cpostal, 2);
you need to use a group by clause in your query.
SELECT LEFT(cpostal,2), COUNT(*) AS total
FROM fiche_personne
GROUP BY LEFT(cpostal,2)
please note that the COUNT(*) isn't the best way to complete the query but I don't know your actual table structure, so you should change this to an actual column name
select count(cpostal) from fiche_personne WHERE cpostal LEFT(cpostal, 2) = 94;
Resource: https://www.w3schools.com/sql/func_mysql_count.asp
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(i INT NOT NULL PRIMARY KEY);
INSERT INTO my_table VALUES
(75012),
(75016),
(94400),
(94500),
(94300),
(78400);
SELECT MIN(i) i, COUNT(*) total FROM my_table GROUP BY LEFT(i,2);
+-------+-------+
| i | total |
+-------+-------+
| 75012 | 2 |
| 78400 | 1 |
| 94300 | 3 |
+-------+-------+

Find duplicates from same table and constraint them from another table in sql

Oh, my title is not the best one and as English is not my main language maybe someone can fix that instead of downvoting if they've understood the issue here.
Basically i have two tables - tourneyplayers and results. Tourneyplayers is like a side table which gathers together tournament information across multiple tables - results, tournaments, players etc. I want to check duplicates from the results table over column day1_best, from single tournament and return all the tourneyplayers who have duplicates.
Tourneyplayers contain rows:
Tourneyplayers
tp_id | resultid | tourneyid
1 | 2 | 91
2 | 21 | 91
3 | 29 | 91
4 | 1 | 91
5 | 3 | 92
Results contains rows:
Results:
r_id | day1_best
1 | 3
2 | 1
3 | 4
.. | ..
21 | 1
.. | ..
29 | 2
Now tourney with id = 91 has in total 4 results, with id's 1,2,21 and 29. I want to return values which have duplicates, so currently the result would be
Result
tp_id | resultid | day1_best
1 | 2 | 1
2 | 21 | 1
I tried writing something like this:
SELECT *
FROM tourneyplayers
WHERE resultid
IN (
SELECT r1.r_id
FROM results AS r1
INNER JOIN results AS r2 ON ( r1.day1_best = r2.day1_best )
AND (
r1.r_id <> r2.r_id
)
)
AND tourneyid =91
But in addition to values which had the same day1_best it chose two more which did not have the same. How could i improve my SQL or rewrite it?
First you JOIN both tables, so you know how the data looks like.
SELECT *
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`;
Then using the same query you GROUP to see what tourneyid, day1_best combination has multiple rows
SELECT `tourneyid`, `day1_best`, count(*) as total
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
GROUP BY `tourneyid`, `day1_best`;
Finally you use the base JOIN and perform a LEFT JOIN to see what rows has a match and show only those rows.
SELECT t.`tp_id`, r.`r_id`, r.`day1_best`
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
LEFT JOIN (SELECT `tourneyid`, `day1_best`, count(*) as total
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
GROUP BY `tourneyid`, `day1_best`
HAVING count(*) > 1) as filter
ON t.`tourneyid` = filter.`tourneyid`
AND r.`day1_best` = filter.`day1_best`
WHERE filter.`tourneyid` IS NOT NULL;
SQL DEMO
OUTPUT
Please try this :
Select tp.tp_id , tp.resultid ,r.day1_best from (Select * from Tourneyplayers
where tourneyid = 91)as tp inner join (select * from Result day1_best in(select
day1_best from result group by day1_best having count(*)>1 ) )as r on tp.resultid
= r.r_id ;

SQL - select rows that have the same value in two columns

The solution to the topic is evading me.
I have a table looking like (beyond other fields that have nothing to do with my question):
NAME,CARDNUMBER,MEMBERTYPE
Now, I want a view that shows rows where the cardnumber AND membertype is identical. Both of these fields are integers. Name is VARCHAR. Name is not unique, and duplicate cardnumber, membertype should show for the same name, as well.
I.e. if the following was the table:
JOHN | 324 | 2
PETER | 642 | 1
MARK | 324 | 2
DIANNA | 753 | 2
SPIDERMAN | 642 | 1
JAMIE FOXX | 235 | 6
I would want:
JOHN | 324 | 2
MARK | 324 | 2
PETER | 642 | 1
SPIDERMAN | 642 | 1
this could just be sorted by cardnumber to make it useful to humans.
What's the most efficient way of doing this?
What's the most efficient way of doing this?
I believe a JOIN will be more efficient than EXISTS
SELECT t1.* FROM myTable t1
JOIN (
SELECT cardnumber, membertype
FROM myTable
GROUP BY cardnumber, membertype
HAVING COUNT(*) > 1
) t2 ON t1.cardnumber = t2.cardnumber AND t1.membertype = t2.membertype
Query plan: http://www.sqlfiddle.com/#!2/0abe3/1
You can use exists for this:
select *
from yourtable y
where exists (
select 1
from yourtable y2
where y.name <> y2.name
and y.cardnumber = y2.cardnumber
and y.membertype = y2.membertype)
SQL Fiddle Demo
Since you mentioned names can be duplicated, and that a duplicate name still means is a different person and should show up in the result set, we need to use a GROUP BY HAVING COUNT(*) > 1 in order to truly detect dupes. Then join this back to the main table to get your full result list.
Also since from your comments, it sounds like you are wrapping this into a view, you'll need to separate out the subquery.
CREATE VIEW DUP_CARDS
AS
SELECT CARDNUMBER, MEMBERTYPE
FROM mytable t2
GROUP BY CARDNUMBER, MEMBERTYPE
HAVING COUNT(*) > 1
CREATE VIEW DUP_ROWS
AS
SELECT t1.*
FROM mytable AS t1
INNER JOIN DUP_CARDS AS DUP
ON (T1.CARDNUMBER = DUP.CARDNUMBER AND T1.MEMBERTYPE = DUP.MEMBERTYPE )
SQL Fiddle Example
If you just need to know the valuepairs of the 3 fields that are not unique then you could simply do:
SELECT concat(NAME, "|", CARDNUMBER, "|", MEMBERTYPE) AS myIdentifier,
COUNT(*) AS count
FROM myTable
GROUP BY myIdentifier
HAVING count > 1
This will give you all the different pairs of NAME, CARDNUMBER and MEMBERTYPE that are used more than once with a count (how many times they are duplicated). This doesnt give you back the entries, you would have to do that in a second step.