Sql - order by number of conditions satisfied - mysql

Suppose I have a query with multiple conditions that are in the OR relation like this:
SELECT * FROM TABLE WHERE (c1) OR (c2) OR (c3) OR ...
I do not want results to be ordered based on the number of condition they satisfied .this means records that satisfied c1 and c2 and c3 showed first(3 conditions),then the records that satisfy c1 and c2,or c1 and c3 ,or c2 and c3(2 conditions) and at the end records that satisfy c1 or c2 or c3

Make an expression that looks like this:
( CASE WHEN c1 THEN 1 ELSE 0 END
+ CASE WHEN c2 THEN 1 ELSE 0 END
+ CASE WHEN c3 THEN 1 ELSE 0 END)
It will provide you the number of conditions satisfied by the current record.

Related

Ignore parameter in WHERE clause if it is set to null

I have a table which looks like this:
id c1 c2 c3 c4
1 2 3 4 5
2 2 4 4 5
I have a query which selects an object from table based on values in columns:
SELECT * FROM table WHERE c1= '2' and c2 = '3' and c3 = '4' and c4 = '5'
How would I ignore a part of WHERE condition if it is set to null?
For example if I'd query like:
SELECT * FROM table WHERE c1='2' and c2= null and c3 = '4' and c4 = '5'
I'd get both objects from table. Thank you.
Since there are not any nulls in your columns you can use COALESCE() like this:
SELECT *
FROM tablename
WHERE c1 = COALESCE(#p1, c1)
AND c2 = COALESCE(#p2, c2)
AND c3 = COALESCE(#p3, c3)
AND c4 = COALESCE(#p4, c4)
if you want to completely ignore the null, you can check with in operator. you can use the COALESCE function.
SELECT * FROM table WHERE COALESCE(c1, '2') = '2' and COALESCE(c2,'3')='3' and COALESCE(c3, '4') = '4' and COALESCE(c4, '5') = '5'
This will match the c1 column for value 2 and nulls. in effect ignore any nulls.
However if you just want c2 to be ignored just use the coalesce on c2 alone

Remove rows that do not differ from the previous row in MySQL

Suppose I have a table that records changes to my database over time:
TimeOfChange FieldA FieldB FieldC
-------------------------------------
2019-01-01 A1 B1 C1 /*(R1)*/
2019-01-02 A2 B2 C1 /*(R2)*/
2019-01-03 A2 B2 C1 /*(R3)*/
2019-01-05 A1 B1 C2 /*(R4)*/
2019-01-07 A1 B1 C1 /*(R5)*/
My database has many rows where nothing significant changed, eg row (R3) is the same as (R2).
I would like to remove these rows. I have found many references on how to use a common table expression to remove duplicate rows from the table. So it's possible to remove the duplicate (ignoring the TimeOfChange column) rows. But this will remove (R5) as well because it is the same as R1. I only want to remove the rows that have the same ABC values as the previous row, when ordered by the TimeOfChange column. How do I do that?
edit: You can assume that TimeOfChange values are all unique
Assuming the TimeOfChange is unique, you can do:
delete
from data
where TimeOfChange in (
select TimeOfChange
from (
select d2.TimeOfChange
from data d1
join data d2
where d2.TimeOfChange in (
select min(x.TimeOfChange)
from data x
where x.TimeOfChange>d1.TimeOfChange
) and d1.FieldA=d2.FieldA and d1.FieldB=d2.FieldB and d1.FieldC=d2.FieldC
) as q
);
So you first want to determine which rows are the "next" and then check if the "next" has the same values as the "current". For those the "next" would form a result set that you want to use in DELETE. The select * from data is there to circumvent the reuse of the table in DELETE and in the subquery.
You probably will get much better performance if you separate the logic into a stored procedure and store the id's for rows to be deleted into a temp table.
See DB Fiddle
Presuming, you really meant "when the same A, B, C occurred on the most recent day prior that had any data", this should be usable to identify the rows that need removed:
SELECT t2.TimeOfChange, t2.FieldA, t2.FieldB, t2.FieldC
FROM (
SELECT tMain.TimeOfChange, tMain.FieldA, tMain.FieldB, tMain.FieldC
, MAX(tPrev.TimeOfChange) AS prevTimeOfChange
FROM t AS tMain
LEFT JOIN t AS tPrev ON t.TimeOfChange> tPrev.TimeOfChange
GROUP BY tMain.TimeOfChange, tMain.FieldA, tMain.FieldB, tMain.FieldC
) AS t2
INNER JOIN t AS tPrev2
ON t2.prevTimeOfChange = tPrev2.TimeOfChange
AND t2.FieldA = tPrev2.FieldA
AND t2.FieldB = tPrev2.FieldB
AND t2.FieldC = tPrev2.FieldC
This can then be used in a DELETE with some indirection to force a temp table to be created.
DELETE td
FROM t AS td
WHERE (td.TimeOfChange, td.FieldA, td.FieldB, td.FieldC)
IN (SELECT * FROM ([the query above]) AS tt) -- Yes, you have to wrap the query from above in a select * so mysql will not reject it.
;
However, after getting this far, what happens when....
2019-01-01 A1 B1 C1
2019-01-02 A2 B2 C1
2019-01-03 A2 B2 C1
2019-01-04 A1 B1 C2
2019-01-05 A1 B1 C3
2019-01-05 A1 B1 C1
2019-01-06 A1 B1 C3
2019-01-07 A1 B1 C1
becomes
2019-01-01 A1 B1 C1
2019-01-02 A2 B2 C1
2019-01-04 A1 B1 C2
2019-01-05 A1 B1 C3
2019-01-05 A1 B1 C1
2019-01-07 A1 B1 C1
Does a second pass now need made to remove the 2019-01-07 entry?
Are you going to run the query repeatedly until no rows are affected?

how do i eliminate a particular value when an id has more than one value in mysql

I have a mysql query which returns more than one row for few ID's with different values. In such a case i need to eliminate the ID's with certain data.
Example
I need to elimate A1 for all those ID's which has more than one name and else if it has only one value A1 then i should be able to display it.
Result Should look like:
ID Name Value
1 A1 AA
1 B1 AB
2 C1 CC
3 A1 AA
4 A1 AA
4 E1 AD
4 B1 AB
Please a solution for this
This is probably very ugly, but at least gets the job done:
select id, name, value from (
select f.*, c.count
from <TABLE> f, (select *, count(*) as 'count' from <TABLE> group by id) c
where f.id = c.id
) c
where (name = 'A1' and count = 1) or name != 'A1'
group by id
you will get the 'first' row for remaining (not random) for id = 4

Mysql SELECT COUNT(COL) with a condition

I have a table with some data like
id group_id f1 f2 f3
1 1 a b
2 1 c
3 2 a c
How can i retrieve one row with group_id and count of rows for each field satisfying some textual condition?
Like that:
MY_MAGIC_SELECT(`f1`='a',`f3`='c');
must return
group_id f1 f2 f3
1 1 0 0
2 1 0 1
Using a sequence of SUM(CASE...) aggregate functions to represent each of your conditions should do it. The CASE returns a 0 or 1 if the condition is matched, and the SUM() adds the result. The GROUP BY is applied on the group_id.
SELECT
group_id
SUM(CASE WHEN f1 = 'a' THEN 1 ELSE 0 END) AS f1,
SUM(CASE WHEN f2 = 'b' THEN 1 ELSE 0 END) AS f2,
/* f3 = 'b' isn't in your "magic select" but here it is anyway... */
SUM(CASE WHEN f3 = 'c' THEN 1 ELSE 0 END) AS f3
FROM
yourtable
GROUP BY group_id
Specifically for MySQL, you don't need the CASE since the boolean expression f1 = 'a' will itself return a 1 or 0. So you can simplify it to the example below. This is not portable to any RDBMS, however.
SELECT
group_id
SUM(f1 = 'a') AS f1,
SUM(f2 = 'b') AS f2,
SUM(f3 = 'c') AS f3
FROM
yourtable
GROUP BY group_id
Here is a quick demonstration on SQLfiddle.com
Well, it is simple MySQL and you need to learn this. Please check this out:
http://www.w3schools.com/sql/sql_where.asp
http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html
SELECT column_name(s)
FROM table_name
WHERE column_name operator value
for example
SELECT * FROM Persons
WHERE City='Sandnes'

Condition in Select statement….. T SQL

I have a table1 with columns as C1, C2, C3 and C4
All these columns stores bit value(true or false).
How to write a select query which uses the logical operations on these columns and gets me the final result?
Ex.:
Select ((C1 OR C2) AND (C3 OR C4)) AS FinalResult
from table1
Bitwise Operators are supported for bit columns:
Select ((C1 | C2) & (C3 | C4)) AS FinalResult
from table1
When both operands are bit, the result is going to be same as if logical operators were applied.
Just test to see if it is equal to 1 (true):
Select CASE WHEN (C1 = 1 OR C2 = 1) AND (C3 = 1 OR C4 = 1) THEN 1 ELSE 0 END AS FinalResult
from table1