Mysql combinations of multiple coloumns - mysql

I have my table in this format
item A B C D
i1 4 0 2 0
i2 0 2 1 0
i3 2 0 0 2
i4 3 0 1 1
And, I'm looking for output where two columns are taken in combinations and if both elements value is >0 output value is taken as 1. And total count is calculated from all records
w1 w2 out
A B 0
A C 2
A D 2
B C 1
B D 0
C D 1
i,e for columns (A,C)>0 only i1 and i4 satisfy.So out=2
So far, I have solved this by querying for each item and then summing the value in php. Can this be possible entirely by sql query?

You can do it in SQL, but I think you still have to consider all the different combinations. Here is one approach using union all and conditional aggregation:
select col1name, col2name,
sum(col1 > 0 and col2 > 0)
from (select 'A' as col1name, 'B' as col2name, A as col1, B as col2
from t
union all
select 'A', 'C', A, C
from t
union all
select 'A', 'D', A, D
from t
union all
select 'B', 'C', B, C
from t
union all
select 'B', 'D', B, D
from t
union all
select 'C', 'D', C, D
from t
) t
EDIT:
There is another way, if you unpivot the data. This starts with this query:
select item, n.colname,
(case when n.colname = 'A' then A
when n.colname = 'B' then B
when n.colname = 'C' then C
else D
end) as colval
from t cross join
(select ';A' as colname union all select 'B' union all select 'C' union all select 'D'
);
We can now do a self join on the query to get all combinations and aggregate to get the results:
select col1.colname, col2.colname,
sum(col1.colval > 0 and col2.colval > 0)
from (select item, n.colname,
(case when n.colname = 'A' then A
when n.colname = 'B' then B
when n.colname = 'C' then C
else D
end) as colval
from t cross join
(select ';A' as colname union all select 'B' union all select 'C' union all select 'D'
)
) col1 join
(select item, n.colname,
(case when n.colname = 'A' then A
when n.colname = 'B' then B
when n.colname = 'C' then C
else D
end) as colval
from t cross join
(select ';A' as colname union all select 'B' union all select 'C' union all select 'D'
)
) col2
on col1.item = col2.item and
col1.colname < col2.colname
group by col1.colname, col2.colname;
This version is simpler if you have more than four columns. The number of combinations in the first methods will quickly become cumbersome.

Related

make 2-dimension coordinate using mysql select results

I have question about mysql queries.
I have a table which have data below.
From To Weight
--------------
A B 1
A C 3
B C 2
D E 4
And I want to get sql result like below..
(?) A B C D E
----------------------
A 0 1 3 0 0
B 0 0 2 0 0
C 0 0 0 0 0
D 0 0 0 0 4
E 0 0 0 0 0
And what data is in original table is not determined.
How can I acheive this?
If you know the original columns, you can do:
select c.col1,
sum(case when to = 'A' then weight else 0 end) as a,
sum(case when to = 'B' then weight else 0 end) as b,
sum(case when to = 'C' then weight else 0 end) as c,
sum(case when to = 'D' then weight else 0 end) as d,
sum(case when to = 'E' then weight else 0 end) as d
from (select 'A' as col1 union all select 'B' union all select 'C' union all select 'D' union all select 'E'
) c left join
t
on t.from = c.col1
group by c.col1;
If you don't know the original columns, you could combine the values into a single string:
select col1.col,
group_concat(col2.col, ':', t.weight order by col2.col)
from ((select `from` as col from t
) union -- on purpose to remove duplicates
(select `to` from t
)
) col1 cross join
((select `from` as col from t
) union -- on purpose to remove duplicates
(select `to` from t
)
) col2 left join
t
on col1.col = t.`from` and col2.col = t.`from`
group by col1.col;
If you actually want separate columns and don't know the values, then you would need dynamic SQL.

SQL-Print column name based on value and condition

I have been trying to print column names based on condition and value.
My problem is this
If two all the columns in the two rows like for data x and y have value yes the it should print those column names otherwise not
My code:
select 'A' from world.city where A = 'yes' AND data=y and data=x union all
select 'B' from world.city where B= 'yes' AND data=y and data=x union all
select 'C' from world.city where C= 'yes' AND data=y and data=x union all
select 'D' from world.city where D= 'yes' AND data=y and data=x union all
select 'E' from world.city where E= 'yes' AND data=y and data=x;
It is not giving perfect results.
Do a sum and union all then filter the rows with sum('yes') is equal to 2. See below.
select colname
from (
select 'A' as colname,sum(case when A='yes' then 1 else 0 end) col
from tbl where data in ('X','Y')
union all
select 'B',sum(case when B='yes' then 1 else 0 end)
from tbl where data in ('X','Y')
union all
select 'C',sum(case when C='yes' then 1 else 0 end)
from tbl where data in ('X','Y')
union all
select 'D',sum(case when D='yes' then 1 else 0 end)
from tbl where data in ('X','Y')
union all
select 'E',sum(case when E='yes' then 1 else 0 end)
from tbl where data in ('X','Y')) tab
where col = 2;
Result:
colname
B
D

How to Group and display count of each type of data?

Suppose I have a column which has three types of data like A, B, C. I want to group and count the number of each type.
For example if A is 3 times in column , B is 2 times and C is 1 time.
It should display as:
A B C
3 2 1
I would appreciate your help. Thankyou.
If you want the data in one row, you can use conditional aggregation:
select sum(col = 'a') as A, sum(col = 'b') as b, sum(col = 'c') as c
from t;
You can try the more explicit:
select sum(case when col = 'a' then 1 else 0 end) as A,
sum(case when col = 'b' then 1 else 0 end) as b,
sum(case when col = 'c' then 1 else 0 end) as c
from t;
I would actually suggest the following query:
SELECT
data, COUNT(*) AS cnt
FROM yourTable
GROUP BY data
This would generate counts in row form, e.g.
A 3
B 2
C 1
Most of the time this would meet your needs. If you instead really need columns you can try this:
SELECT
SUM(CASE WHEN data = 'A' THEN 1 ELSE 0 END) AS A,
SUM(CASE WHEN data = 'B' THEN 1 ELSE 0 END) AS B,
SUM(CASE WHEN data = 'C' THEN 1 ELSE 0 END) AS C
FROM yourTable
This would generate your literal expected output:
A B C
3 2 1

Insert new row for binary systems with SQL

I have the following table
(cl1 , cl2)
---- ----
(a , 1)
(a , 2)
(b , 2)
(c , 1)
(c , 2)
each a , b ,c can take two values (1 or 2 or both).
My question is :
How to insert a new row (with 0 on cl2) for all the cl1 that have only 1 or 2 and NOT the both in the example. I would like to insert the following row :
----
(b , 0)
----
I'm sure there are better ways, but here is one way to do it using group by and a having clause to enforce your rules (I'm assuming Oracle syntax):
insert into tbl (cl1, cl2)
(select cl1, 0
from tbl
group by cl1
having count(case when cl2 in (1, 2) then 'X' end) != 0 -- contains 1 or 2
and (count(case when cl2 = 1 then 'X' end) = 0 -- but not both
or count(case when cl2 = 2 then 'X' end) = 0)
)
EDIT
A much simpler way:
insert into tbl (cl1, cl2)
(select cl1, 0
from tbl
where cl2 in (1, 2)
group by cl1
having count(distinct cl2) = 1
)
I am assuming that the BD is Oracle. Hope the below snippet helps.
SELECT B.CL1,
0
FROM
(SELECT A.CL1,
CASE
WHEN WMSYS.WM_CONCAT(A.CL2) LIKE '%1%'
AND WMSYS.WM_CONCAT(A.CL2) LIKE '%2%'
THEN 'both'
ELSE 'one'
END rnk
FROM
(SELECT 'a' cl1,1 cl2 FROM dual
UNION ALL
SELECT 'a' cl1,2 cl2 FROM dual
UNION ALL
SELECT 'b' cl1,2 cl2 FROM dual
UNION ALL
SELECT 'c' cl1,1 cl2 FROM dual
UNION ALL
SELECT 'c' cl1,2 cl2 FROM dual
)A
GROUP BY A.CL1
)B
WHERE B.rnk = 'one';
CREATE TABLE TestTable (cl1 VARCHAR(2), cl2 INT);
INSERT INTO TestTable (cl1, cl2) VALUES ('a', 1), ('a', 2), ('b', 1), ('c', 1), ('c', 2);
INSERT INTO TestTable (cl1, cl2)
SELECT cl1, 0
FROM TestTable
WHERE cl1 NOT IN (
SELECT cl1
FROM TestTable
WHERE cl2 IN (1, 2)
GROUP BY cl1
HAVING COUNT(DISTINCT cl2) = 2
);
MySQL Demo: http://rextester.com/XWHGF50183
The below block returns the cl1 those have the cl2 is 1 and 2. Based on the result using NOT IN you can achieve the result.
SELECT cl1
FROM TestTable
WHERE cl2 IN (1, 2)
GROUP BY cl1
HAVING COUNT(DISTINCT cl2) = 2
Help from this answer
Here you go:
insert into [YOUR TABLE NAME]
select cl1,0 from [YOUR TABLE NAME]
group by cl1 having count(distinct cl2)<> 2
;

MySQL matrix multiplication

I am trying to write matrix multiplication for MySQL and am kinda stuck:
basically, my matrices are stored in format
[row#, column#, matrixID, value], so for example matrix [3 x 2] would be something like:
[row#, column#, matrixID, value]
1 1 mat01 1
1 2 mat01 2
1 3 mat01 3
2 1 mat01 4
2 2 mat01 5
2 3 mat01 6
being equivalent to: [[1 2 3],[4 5 6]]
following does calculation of single element of matrix1 * matrix2 quite well:
SELECT SUM(row1.`val` * col2.`val`)
FROM matValues row1
INNER JOIN `matValues` col2
WHERE row1.`row` = 1 AND row1.`mID`='matrix1' AND
col2.`mID`='matrix2' AND col2.`col` = 1 AND row1.col = col2.row
wrapping this into function and then using another function to iterate over row and column numbers might work, but I have problems with generating this set of numbers and iterating over them using SQL.
Any advice / suggestions are welcome
Try:
select m1.`row#`, m2.`column#`, sum(m1.value*m2.value)
from matValues m1
join matValues m2 on m2.`row#` = m1.`column#`
where m1.matrixID = 'mat01' and m2.matrixID = 'mat02'
group by m1.`row#`, m2.`column#`
Example here.
(Replace 'mat01' and 'mat02' with suitable matrixID values.)
You can do the entire calculation in SQL. You only give an example with a single matrix, which because it is not square, cannot be multiplied by itself.
Here is the idea:
SELECT mout.row, mout.col, SUM(m1.value*m2.value)
FROM (select distinct row from matValues cross join
select distinct COL from matValues
) mout left outer join
matValues m1
on m1.row = mout.row left outer join
matValues m2
on m2.col = mout.col and
m2.row = m1.col
I know this is SQL-Server syntax, but it should give you a start on the corresponding MySql syntax. The sparse matrix nature seems to handle well.
with I as (
select * from ( values
(1,1, 1),
(2,2, 1),
(3,3, 1)
) data(row,col,value)
)
,z_90 as (
select * from ( values
(1,2, 1),
(2,1,-1),
(3,3, 1)
) data(row,col,value)
)
,xy as (
select * from ( values
(1,2, 1),
(2,1, 1),
(3,3, 1)
) data(row,col,value)
)
,x_90 as (
select * from ( values
(1,1, 1),
(2,3, 1),
(3,2,-1)
) data(row,col,value)
)
select
'I * z_90' as instance,
a.row,
b.col,
sum( case when a.value is null then 0 else a.value end
* case when b.value is null then 0 else b.value end ) as value
from I as a
join z_90 as b on a.col = b.row
group by a.row, b.col
union all
select
'z_90 * xy' as instance,
a.row,
b.col,
sum( case when a.value is null then 0 else a.value end
* case when b.value is null then 0 else b.value end ) as value
from z_90 as a
join xy as b on a.col = b.row
group by a.row, b.col
union all
select
'z_90 * x_90' as instance,
a.row,
b.col,
sum( case when a.value is null then 0 else a.value end
* case when b.value is null then 0 else b.value end ) as value
from z_90 as a
join x_90 as b on a.col = b.row
group by a.row, b.col
order by instance, a.row, b.col
yields:
instance row col value
----------- ----------- ----------- -----------
I * z_90 1 2 1
I * z_90 2 1 -1
I * z_90 3 3 1
z_90 * x_90 1 3 1
z_90 * x_90 2 1 -1
z_90 * x_90 3 2 -1
z_90 * xy 1 1 1
z_90 * xy 2 2 -1
z_90 * xy 3 3 1
However, I suggest you also check out performing this on your graphics card. NVIDIA has a good example of implementing matrix multiplication in theri C Programming Guide.