Selecting values present in one column but not in all other columns - php

Suppose I have columns col1, col2, col3, col4 in myTable and I need to print out the values exclusive to only one column .
So if the above looks like
col1 col2 col3 col4
s e c b
c c a s
n s e a
d d q c
Then the output should be n, q b since they are exclusive only to col1, col3 and col4 respectively.
How can I achieve this through a query in mysql php?
EDIT The duplicates dont have to be in a single row .I have changed the the table layout now to make it clear.

If you are looking for a SQL-only solution, you can do a query per column like this:
SELECT
col1 AS unique_on_col1
FROM table
WHERE col1 NOT IN (SELECT col2 FROM table)
AND col1 NOT IN (SELECT col3 FROM table)
AND col1 NOT IN (SELECT col4 FROM table)
It's possible to combine all four queries with UNION but that may not be necessary depending on what you want to do with the data. Also, this query should not perform very well with large datasets.

One slightly more compact way of getting all of them at once:
select distinct col1
from myTable
where col1 not in (select a.col1
from myTable a join myTable b
on a.col1 = b.col2 or a.col1=b.col3 or a.col1=b.col4)
union
select distinct col2
from myTable
where col2 not in (select a.col2
from myTable a join myTable b
on a.col2 = b.col1 or a.col2=b.col3 or a.col2=b.col4)
union
select distinct col3
from myTable
where col3 not in (select a.col3
from myTable a join myTable b
on a.col3 = b.col1 or a.col3=b.col2 or a.col3=b.col4)
union
select distinct col4
from myTable
where col4 not in (select a.col4
from myTable a join myTable b
on a.col4 = b.col1 or a.col4=b.col2 or a.col4=b.col3)

$sql = "
SELECT DISTINCT 'col1' as descr,col1 as val FROM myTable
UNION
SELECT DISTINCT 'col2' as descr,col2 as val FROM myTable
UNION
SELECT DISTINCT 'col3' as descr,year as val FROM myTable";
$result = #mysql_query($sql, $con) or die(mysql_error());
while($row = mysql_fetch_array($result)) {
$make_array[$row['descr']][]=$row['val'];
}
I'm guessing this should work. Dint try the code out but give this one a shot and let us know.

Try This:
SELECT col1 AS unique_on_col1
FROM table
WHERE col1 NOT IN (SELECT col2 FROM table)
AND col1 NOT IN (SELECT col3 FROM table)
AND col1 NOT IN (SELECT col4 FROM table)

Related

ORDER BY RAND() for multiple columns (shuffle content of each column vertically)

I'm looking for a mysql solution to have several columns output a random field from that column.
The query I have now only selects the entire row randomly but does not randomize the separated columns.
$sql = "SELECT col1, col2, col3, col4 FROM table ORDER BY RAND() limit 4";
I tried subqueries but I'm not familiar with that so if anyone could help ...
Try this:
SELECT CASE rnd
WHEN 1 THEN col1
WHEN 2 THEN col2
WHEN 3 THEN col3
WHEN 4 THEN col4
END AS col
FROM (
SELECT col1, col2, col3, col4,
FLOOR(RAND() * 4) + 1 AS rnd
FROM mytable
ORDER BY RAND() ) AS t
Expression FLOOR(RAND() * 4) + 1 generates a random number between 1 and 4 (inclusive). The outer query uses this number to randomly pick one of the 4 columns of the table.
Demo here
Edit:
If you want to shuffle columns the you can use the following query:
SELECT CASE FIND_IN_SET(1, rnd)
WHEN 1 THEN col1
WHEN 2 THEN col2
WHEN 3 THEN col3
WHEN 4 THEN col4
END AS c1,
CASE FIND_IN_SET(2, rnd)
WHEN 1 THEN col1
WHEN 2 THEN col2
WHEN 3 THEN col3
WHEN 4 THEN col4
END AS c2,
CASE FIND_IN_SET(3, rnd)
WHEN 1 THEN col1
WHEN 2 THEN col2
WHEN 3 THEN col3
WHEN 4 THEN col4
END AS c3,
CASE FIND_IN_SET(4, rnd)
WHEN 1 THEN col1
WHEN 2 THEN col2
WHEN 3 THEN col3
WHEN 4 THEN col4
END AS c4
FROM (
SELECT col1, col2, col3, col4,
(SELECT GROUP_CONCAT(i ORDER BY RAND())
FROM (SELECT 1 AS i UNION ALL SELECT 2 UNION ALL
SELECT 3 UNION ALL SELECT 4) t) AS rnd
FROM mytable) AS t
Demo here
If every resulting row has to be independent then there is no other way than to select 16 random rows (once for each cell in your 4x4 resulting table).
SELECT
(SELECT col1 FROM `table` ORDER BY RAND() LIMIT 1) AS col1,
(SELECT col2 FROM `table` ORDER BY RAND() LIMIT 1) AS col2,
(SELECT col3 FROM `table` ORDER BY RAND() LIMIT 1) AS col3,
(SELECT col4 FROM `table` ORDER BY RAND() LIMIT 1) AS col4
FROM `table`
LIMIT 4
I think it'd be simpler if you randomize the columns in PHP as well but as a fun challenge I thought I would do it like below.
It'll give you random 4 rows and randomize/shuffle the column values.
Fist it simply GROUP_CONCAT values 1,2,3,4 but randomize the order ..then extract the indexes of numbers using FIND_IN_SET..then selects the col values based on these indexes using ELT() function.
SELECT
ELT(FIND_IN_SET(1,rand_indexes),col1,col2,col3,col4) as col1,
ELT(FIND_IN_SET(2,rand_indexes),col1,col2,col3,col4) as col2,
ELT(FIND_IN_SET(3,rand_indexes),col1,col2,col3,col4) as col3,
ELT(FIND_IN_SET(4,rand_indexes),col1,col2,col3,col4) as col4
FROM
(SELECT col1,col2,col3,col4,
(SELECT GROUP_CONCAT(i ORDER BY RAND()) as indexes FROM
(SELECT 1 as i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4)indexes
)as rand_indexes
FROM `table`
)T1
ORDER BY RAND() limit 4
sqlfiddle
UPDATE If you want to shuffle your column vertically like you have mentioned in comment, then you can use this query it.
It basically selects first column 4 rows in random order then joins with 4 random rows of second column and so on...
SELECT T1.col1,T2.col2,T3.col3,T4.col4
FROM
(SELECT col1,#order1:=#order1+1 as i
FROM (SELECT col1 FROM `table` ORDER BY RAND() LIMIT 4) O1,(SELECT #order1:=0) initialize )T1
INNER JOIN
(SELECT col2,#order2:=#order2+1 as i
FROM (SELECT col2 FROM `table` ORDER BY RAND() LIMIT 4) O1,(SELECT #order2:=0) initialize )T2
ON T1.i = T2.i
INNER JOIN
(SELECT col3,#order3:=#order3+1 as i
FROM (SELECT col3 FROM `table` ORDER BY RAND() LIMIT 4) O1,(SELECT #order3:=0) initialize )T3
ON T1.i = T3.i
INNER JOIN
(SELECT col4,#order4:=#order4+1 as i
FROM (SELECT col4 FROM `table` ORDER BY RAND() LIMIT 4) O1,(SELECT #order4:=0) initialize )T4
ON T1.i = T4.i
sqlfiddle shuffle columns vertically
This one will do but I guess I'm sure it's not performing very good:
select * from
(select col1 from table order by rand()) as a,
(select col2 from table order by rand()) as b,
(select col3 from table order by rand()) as c,
(select col4 from table order by rand()) as d
order by rand()
limit 4;
It does a cross join on all 4 tables (giving n^4 rows) and then fetches the first 4 rows of that.
Update because the OP asked about the purpose of a/b/c/d:
The a, b, etc. are just (randomly chosen) aliases for the 4 subqueries and can be seen as (temporary) table names.
They are required for the syntax to refer to the subqueries. In this particular example they are useless, but MySQL (and probably other systems as well) needs them.
In the above statement the column names are already unique, but consider the case when column names are not uniqe and you wanted to perform some operations on the columns, like so:
select concat(a.col1, ' ', c.col1), b.col2, d.col2 from
(select col1 from table order by rand()) as a,
(select col2 from table order by rand()) as b,
(select col1 from table order by rand()) as c,
(select col2 from table order by rand()) as d
where b.col2 > d.col2
order by rand()
limit 4;
Then these aliases a to d are really needed to distinguish e.g. col1 from the 1st and 3rd subselect.
However, #PaulSpiegel's answer is better than mine because I missed the limit 1 in the subqueries.

Join column names from Tab1 with 1 column values of Tab2

I have 2 tables with the following structures:
// tab1:
| ID | Col1 | Col2 | Col3 | Col4 |
|----|------|------|------|------|
| 1 | Val1 | Val2 | Val3 | Val4 |
| 2 | Val5 | Val6 | Val7 | Val8 |
// tab2:
| Name |
|------|
| Col1 |
| Col3 |
I now need to get all values from tab1 and somehow join them with the values of the column of tab2, so that in the frontend all columns from tab1, that are also present in tab2, are bold.
In pseudocode it would look like that:
SELECT Col1, COl2, Col3, Col4 FROM tab1, tab2 WHERE ID=1 AND {possibly a left join on tab2}
The desired output as a table in the fronted could be:
Value 1: Val1
Value 2: Val2
Value 3: Val3
Value 4: Val4
Since col1 and col3 are also in tab2, their values should be bold.
So I just need the appropriate query with a "flag". In the frontend I then would just loop the results and look for the flag. If the flag is set, display the value as bold.
I don't really have influence on the database structure.
Assuming that the table structure is complete and we know all the column names, we can execute the below query to check whether a value exists or not.
select col1 as col1 ,
(select count(*) from tab2 where name = 'col1') col1_exists,
col2 as col2,
(select count(*) from tab2 where name = 'col2') col2_exists,
col3 as col3 ,
(select count(*) from tab2 where name = 'col1') col3_exists
from tab1;
For non zero 'exists' values, we can show the corresponding column value in bold. Here is the SQL Fiddle.
Try this :
SELECT
t.`VALUE`,
(CASE WHEN tab2.Name IS NULL THEN 0 ELSE 1 END) flag
FROM
(
SELECT
Col1 AS `VALUE`,
'Col1' AS colNum
FROM tab1
WHERE ID = 1
UNION
SELECT
Col2 AS `VALUE`,
'Col2' AS colNum
FROM tab1
WHERE ID = 1
UNION
SELECT
Col3 AS `VALUE`,
'Col3' AS colNum
FROM tab1
WHERE ID = 1
UNION
SELECT
Col4 AS `VALUE`,
'Col4' AS colNum
FROM tab1
WHERE ID = 1
) t
LEFT JOIN tab2
ON tab2.`Name` = t.colNum;
SQL FIDDLE
Due to the restrictions with your design, you are not able to do this with MYSQL alone, but you can with the help of PHP:
get the column names from tbl2
use those column names to obtain your results from tbl1
Try the following (assuming you use mysqli):
//get columns from tbl2
$sql = 'SELECT * FROM tbl2';
$result = mysqli_query($conn, $sql);
$cols = [];
while ($row = mysqli_fetch_assoc($result)) {
$cols[] = $row['name'];
}
//get results from tbl1 using column names
$sql = 'SELECT ' . implode(',', $cols) . ' FROM tbl1 WHERE ID=1';
$result = mysqli_query($conn, $sql);
while ($row = mysqli_fetch_assoc($result)) {
var_dump($row);
}

If we are using union, then how to display table name with specific entry

Like I am using union of multiple tables and displaying rows ordered by date with some limit. But I also need to show that specific entry belong to a 'table' table. How to get value of 'table'?
While mentioning required columns you can add another column which will have the name of table.
Like:
SELECT *, 'table1' as table_name FROM table1
UNION
SELECT *, 'table2' as table_name FROM table2
Doing this you can have table identifier in table_name column of the result set and you can use it as you want.
SELECT *, 'table1' FROM `table1`
UNION
SELECT *, 'table2' FROM `table2`
This was easy
$sql = "
SELECT col1, 'table1' , col2, col3 FROM table1
UNION
SELECT col1, 'table2' , col2, col3 FROM table2
UNION
SELECT col1, 'table3' , col2, col3 FROM table3
";
$query= mysqli_query($conn, $sql);
while($row = mysqli_fetch_array($query, MYSQL_NUM)){

Combining two mysql queries

I have two sql queries...
set #count:=0;
select #count:=#count+1 as SNO, col1, col2 FROM table;
I want to combine above queries into a single query. Any Help?
You can simply do this,
select #count:=#count+1 as SNO, col1, col2
FROM table, (SELECT #count:=0) r ;
Just like adding RowNumber for each row
select #rownum:=#rownum+1 ‘rank’,
p.*
from player p, (SELECT #rownum:=0) r
order by score
desc limit 10;
Adding RowNumber in MySQL
As per my understanding,you are looking for Row_Number function in this case. If this is correct, please have a look here
e.g.
Select #count := #count + 1 As SNO, col1, col2
From table ,(SELECT #count:=0) foo
may help
Also you can refer ROW_NUMBER, Partition, and Over in MySQL for more understanding on the same
Combining two queries..
SELECT t1.field1, t1.field2, t2.field1
FROM (query1) as t1, (query2) as t2
WHERE t1.field1= t2.field1
Hope this will works ...
select #count:=#count+1 as SNO, col1, col2 FROM table, (SELECT #count:=0) t;

Check distinct value ignoring other columns data

If I have a table with data like this :
Col1 | Col2 | Col3
111 | a |
222 | b | 1
111 | |
And I wish to select Distinct Col1 only from my temporary table then insert into another table.But with the table above , the second "111" will be selected as well since it has different Col2 data.
Or if I select Distinct Col1 only , the other columns data will be ignored...
So is there any way to solve this problem? I wish to choose only the first inserted row of same Col1 data.
I'm using this query:
mysql_query("INSERT DELAYED INTO Tableb (Col1,Col2,Col3) SELECT DISTINCT Col1,Col2,Col3 FROM TempTable");
Thanks for any reply.
PS: I'm not sure how to specified the title according to my question...perhaps someone can help me.
Maybe something like this (this is probably what you want):
INSERT INTO Tableb
(
Col1,Col2,Col3
)
SELECT
t.Col1,
MAX(t.Col2) AS Col2,
MAX(t.Col3) AS Col3
FROM
TempTable as t
GROUP BY
t.Col1
Or if you want the MIN value. Like this:
INSERT INTO Tableb
(
Col1,Col2,Col3
)
SELECT
t.Col1,
MIN(t.Col2) AS Col2,
MIN(t.Col3) AS Col3
FROM
TempTable as t
GROUP BY
t.Col1
First you need to determine last ID per distinct value of col1, and then you select rows containing this id:
INSERT DELAYED INTO Tableb (Col1,Col2,Col3)
SELECT TempTable.Col1, TempTable.Col2, TempTable.Col3
from TempTable
inner join
(
select Col1, max(ID) ID
from TempTable
group by Col1
) c
ON TempTable.ID = c.ID
Inner query returns ID's to be inserted, so one simply joins them to original table to filter the table.
Substitute max(id) with min(id) if you want first inserted TempTable record.
mysql_query("INSERT DELAYED INTO Tableb (Col1,Col2,Col3) SELECT Col1, MAX(t.Col2) AS Col2, MAX(t.Col3) AS Col3 FROM TempTable GROUP BY Col1");
INSERT DELAYED INTO Tableb (Col1,Col2,Col3) SELECT Col1,Col2,Col3 FROM TempTable GROUP BY Col1 ORDER BY [your way of sorting here]
Does that do it?

Categories