SQL Select rows where col1 or col2 equals variable - mysql

So I want to select rows from table where col1 or col2 equals to variable, but if there is already row selected where col1 equals to variable (variable X) and col2 is anything else (variable Y) then it won't select another row where col2 equals to variable X and col1 equals to that variable Y. Everything ordered by column TIME descending.
Let's say this is my table:
COL1 COL2 TIME COL4
1 2 0 A
1 2 1 B
2 1 2 C
1 3 3 D
3 1 4 E
4 2 5 F
3 4 6 G
1 2 7 H
4 1 8 I
And let's say that variable X equals to 1, then I want to have these rows:
COL1 COL2 TIME COL4
4 1 8 I
1 2 7 H
3 1 4 E
So it won't show me this row
COL1 COL2 TIME COL4
2 1 2 C
because there is already a combination where col1/col2 is 2/1 or 1/2.
Sorry if I explained it in a bad way, but I can't think of better explanation.
Thank you guys.

Making a couple of key assumptions...
SELECT a.*
FROM my_table a
JOIN
( SELECT MAX(time) time
FROM my_table
WHERE 1 IN (COL1,COL2)
GROUP
BY LEAST(col1,col2)
, GREATEST(col1,col2)
) b
ON b.time = a.time;

EDIT: I posted this answer when it was thought that OP's database was SQL Server. But as it turns out, the database is MySQL.
I think this query should do it:
select t.col1, t.col2, t.time, t.col4
from (select t.*,
row_number() over (
partition by
case when col1 < col2 then col1 else col2 end,
case when col1 < col2 then col2 else col1 end
order by time desc) as rn
from tbl t
where t.col1 = x or t.col2 = x) t
where t.rn = 1
order by t.time desc
The key part is defining the row_number partition by clause in such a way that (1, 2) is considered equivalent to (2, 1), which is what the case statements do. Once the partitioning works correctly, you just need to keep the first row of every "partition" (where t.rn = 1) to exclude duplicate rows.

Related

MySQL Query to fetch count of a same successive two rows based on a column value

I need a sql query which will fetch me the count of unique possible combination of a value a to b of col3 based on the col2 value.
Here in the below table the value a to b is there twice(2 to 3 for col1-1 and 2 to 3 for col1-2).Similarly I need the count of such possible a to b fields as they appear successively in the table(which we can identify from col2-2,3)
I have the following table:
col1 col2 col3
1 2 a
1 3 b
1 4 c
2 2 a
2 3 b
2 4 c
Output:
f1 f2 count
a b 2
b c 2
Here col1+col2 is the primary key and the query should be generic for n no of possible successive combination.
As I was looking into possibilities of finding the solution to my problem, I got one by myself...
Below is the query to get the desired output which I wanted, was pretty straight forward.
select a.col3 f1,
b.col3 f2,
count(*) count
from testTable b,testTable a
where
a.col2 = b.col2 -1
and a.col1 = b.col1
group by ev1,ev2;

Adding a new column in SQL which calculates value from other columns

I was trying to create a new column in SQL which has calculated values from other columns in the same table.
Please see the case below
col1 col2
A 1
A 2
B 1
B 2
B 3
I need to create a new column 'col3' that finds the max of col2 grouped by col1. So the result i want is
col1 col2 col3
A 1 2
A 2 2
B 1 3
B 2 3
B 3 3
I would like to know if a query can be something along the below lines
ALTER TABLE table1 ADD col3 AS (SELECT max(col2) GROUPBY col1)
You don't need an ALTER statement and can get the extra column in your SELECT query like
select col1, col2, max(col2) as col3
from tbl1
group by col1

how to achieve concatenation using group by

Suppose there is a table named 'a' with following data:
col1, col2
-----------
1 1
1 2
1 3
2 2
2 3
3 4
then to achieve following results:
col1, col2
--------------
1 6
2 5
3 4
i can run query like :
select col1, sum(col2) from a group by col1.
But suppose my table is:
col1, col2
---------
1 a
1 b
1 c
2 d
2 e
3 f
here col2 is of varchar type not of numeric type.
what will be the sql query to give following results???
col1, col2
------------
1 a,b,c
2 d,e
3 f
i have tried group by on col1 but how to concatenate values in col2???
the problem is that col2 is of varchar type.
In case of MySQL you can use GROUP_CONCAT like this:
SELECT
col1,
GROUP_CONCAT(col2) as col2
FROM demo
GROUP BY col1;
Here is the sqlfiddle.
In case of SQL Server you can use STUFF like this:
SELECT t1.col1,
stuff((SELECT ',' + CAST(t2.col2 as VARCHAR(10))
FROM demo t2 WHERE t1.col1 = t2.col1
FOR xml path('')),1,1,'') col2
FROM demo t1
GROUP BY t1.col1;
Here is the sqlfiddle.
You can use group_concat function in mysql
select
col1,
group_concat(col2) as col2
from table_name
group by col1
Here is a good example, I ran into a similar issue whilst coding up a schedule (working example: www.oldiesplus.com/schedule/)
Here is the link to my question with answer: https://stackoverflow.com/a/27047139

Show only differences between two rows in mysql

Having a (MySQL) audit table containing rows that are similar, is it possible to view only those columns that have different values?
For example, a table containing four columns where column key is primary key, and column id is the identifier to match rows:
key id col1 col2
1 123 B C
2 123 A C
3 456 B C
4 789 B A
5 789 B B
6 987 A C
In the example above I need the query to return only row 1, 2, 4, and 5 as they have matching id, and differing values in col1 and col2, ie B,A and B,A.
key id col1 col2
1 123 B
2 123 A
4 789 A
5 789 B
I know it might not be very efficient solution, but gives what you want. HERE try this:
SELECT A.ID, (CASE A.col1 WHEN B.col1 THEN NULL ELSE B.col1 END), (CASE A.col2 WHEN B.col2 THEN NULL ELSE B.col2 END) FROM tblName A
FULL OUTER JOIN tblName B
ON
A.ID=B.ID
WHERE
(A.col1=B.col1 AND A.Col2<>B.Col2)
OR
(A.col2<>B.col2 AND A.Col1=B.Col1)
INNER JOIN should give same result
This is a bit contrived, in the sense that adding more rows will give very different results - but anyway...
SELECT x.my_key
, x.id
, IF(y.col1=x.col1,'',x.col1) col1
, IF(y.col2=x.col2,'',x.col2) col2
FROM my_table x
JOIN my_table y
ON y.id = x.id
AND y.my_key <> x.my_key
WHERE (y.col1 <> x.col1 OR y.col2 <> x.col2)
ORDER
BY my_key;
Thanks for all responses which guided me.
Using your suggestions I made the sql like this:
SELECT
T1.KEY,
T1.ID,
CASE T2.COL1_DISTINCT_VALUES WHEN 1 THEN NULL ELSE T1.COL1 END AS COL1,
CASE T2.COL2_DISTINCT_VALUES WHEN 1 THEN NULL ELSE T1.COL2 END AS COL2
FROM
TAB1 T1
INNER JOIN
(
SELECT
ID,
COUNT(DISTINCT COL1) AS COL1_DISTINCT_VALUES,
COUNT(DISTINCT COL2) AS COL2_DISTINCT_VALUES
FROM
TAB1
GROUP BY
ID
) T2
ON T1.ID=T2.ID
WHERE
T2.COL1_DISTINCT_VALUES > 1
OR T2.COL2_DISTINCT_VALUES > 1
ORDER BY
KEY,ID;

Splitting a result into three columns

Say I have a table 'alphabet'. This is just a basic representation/example.
id word
1 a
2 b
3 c
4 d
5 e
6 f
7 g
8 h
9 i
10 j
11 k
12 l
13 m
Now assume I am restricted to just a single query (with subqueries) due to a language restriction or otherwise.
I want my 'result' to be as follows:
row col1 col2 col3
1 a b c
2 d e f
3 g h i
4 j k l
5 m
Now I've gotten somewhat close to this by emulating a Full Outer Join in MySQL by following the instructions found here: Full Outer Join in MySQL combined with a sub-query on the same table using something along the lines of:
SELECT id,word FROM table WHERE MOD(id,3)=1
This isn't particularly perfect, as it requires me to assume that the ids follow each-other perfectly sequentially, but I haven't been able to think of a better method at the time. Since last I recall, LIMIT and OFFSET do not take sub-queries.
However, following this thought through, results into something along the lines of:
row col1 col2 col3
1 a
2 d
3 g
4 j
5 m
6 b
7 e
8 h
9 k
10 c
11 f
12 i
13 l
13 m
Is there a way to get my desired format?
And note that normally, the desired way to do this is indeed to just do three calls with a limit-offset call based on a count(). But /is this possible/ to be done in a single call?
I doesn't found any use case for this, but it is what you want:
SELECT
FLOOR((id - 1)/3) + 1 id,
MAX(CASE WHEN MOD(id - 1,3) = 0 THEN word END) col1,
MAX(CASE WHEN MOD(id - 1,3) = 1 THEN word END) col2,
MAX(CASE WHEN MOD(id - 1,3) = 2 THEN word END) col3
FROM tbl
GROUP BY FLOOR((id - 1)/3)
SQLFIDDLE DEMO
Notice, that this will work only in case when you have sequential Id starting from 1.
Is this what you need?
SELECT FLOOR((col1.id - 1) / 3 + 1) AS id, col1.word AS col1, col2.word AS col2, col3.word AS col3
FROM alphabet col1
LEFT JOIN alphabet col2 ON col1.id = col2.id - 1
LEFT JOIN alphabet col3 ON col2.id = col3.id - 1
WHERE col1.id % 3 = 1;
How about something like
Select t1.id as `row`, t1.word as col1, t2.word as col2, t3.word as col3
From alphabet t1
left join alphabet t2 on t2.id = t1.id + 5
left join alphabet t3 on t3.id = t1.id + 10
Where t1.id <= 5
Taking Halmet Hakobyan's answer, finishing this off:
SELECT
FLOOR((rank - 1)/3) + 1 rank,
MAX(CASE WHEN MOD(rank - 1,3) = 0 THEN word END) col1,
MAX(CASE WHEN MOD(rank - 1,3) = 1 THEN word END) col2,
MAX(CASE WHEN MOD(rank - 1,3) = 2 THEN word END) col3
FROM (SELECT #rn:=#rn+1 AS rank, `id`,`word` from tbl) as tbl, (SELECT #rn:=0) t2
GROUP BY FLOOR((rank - 1)/3)
SQLFIDDLE DEMO
This will work even if the ids are not in sequence.