MySQL - Finding how much duplicates are inside the same table given - mysql

Considering I have the following two sets of rows (same type) in a WHERE clause:
A B
1 1
2 2
3 4
I need to find how many A is in B
For example, for the given table above, it would be 66% since 2 out of 3 numbers are in B
Another example:
A B
1 1
2 2
3 4
5
3
Would give 100% since all of the numbers in A are in B
Here is what I tried myself: (Doesn't work on all test cases..)
DROP PROCEDURE IF EXISTS getProductsByDate;
DELIMITER //
CREATE PROCEDURE getProductsByDate (IN d_given date)
BEGIN
SELECT
Product,
COUNT(*) AS 'total Number',
(SELECT
(SELECT COUNT(DISTINCT Part) FROM products WHERE Product=B.Product) - COUNT(*)
FROM
products AS b2
WHERE
b2.SOP < B.SOP AND b2.Part != B.Part) AS 'New Parts',
CONCAT(round((SELECT
(SELECT COUNT(DISTINCT Part) FROM products WHERE Product=B.Product) - COUNT(*)
FROM
products AS b2
WHERE
b2.SOP < B.SOP AND b2.Part != B.Part)/count(DISTINCT part)*100, 0), '%') as 'Share New'
FROM
products AS B
WHERE
b.SOP < d_given
GROUP BY Product;
END//
DELIMITER ;
CALL getProductsByDate (date("2018-01-01"));
Thanks.

Naming your tables TA and TB respectively you could try something like this (test made on MSSQL and Mysql at moment)
SELECT ROUND(SUM(PERC) ,4)AS PERC_TOT
FROM (
SELECT DISTINCT TA.ID , 1.00/ (SELECT COUNT(DISTINCT ID) FROM TA) AS PERC
FROM TA
WHERE EXISTS ( SELECT DISTINCT ID FROM TB WHERE TB.ID=TA.ID)
) C;
Output with your first sample data set:
PERC_TOT
0,6667
Output with your second sample data set:
PERC_TOT
1,0000
Update (I made the original for two tables, as I was thinking at solution). This is for one single table (is almost the same than the former query): (I used ID1 for column A and ID2 for column B)
SELECT ROUND(SUM(PERC) ,4)AS PERC_TOT
FROM (
SELECT DISTINCT TA.ID1 , 1.00/ (SELECT COUNT(DISTINCT ID1) FROM TA) AS PERC
FROM TA
WHERE EXISTS ( SELECT DISTINCT ID2 FROM TA AS TB WHERE TB.ID2=TA.ID1)
) C;

Related

SQL - Split a column into two columns in Mysql

I have this table. Considering the id starts from 0.
Table 1
ID Letter
1 A
2 B
3 C
4 D
6 E
I need following output
Col1 Col2
NULL A
B C
D NULL
E NULL
I tried using union with id, id - 1 and id + 1, but I couldn't figure out how to get letter based on ids, also tried even odd logic but nothing worked.
Any help is appreciated.
Thank you
You didn't post the database engine, so I'll assume PostgreSQL where the modulus operand is %.
The query should be:
select o.letter, e.letter
from (
select id, letter, id as base from my_table where id % 2 = 0
) o full outer join (
select id, letter, (id - 1) as base from my_table where id % 2 <> 0
) e on e.base = o.base
order by coalesce(o.base, e.base)
Please take the following option with a grain of salt since I don't have a way of testing it in MySQL 5.6. In the absence of a full outer join, you can perform two outer joins, and then you can union them, as in:
select * from (
select o.base, o.letter, e.letter
from (
select id, letter, id as base from my_table where id % 2 = 0
) o left join (
select id, letter, (id - 1) as base from my_table where id % 2 <> 0
) e on e.base = o.base
union
select e.base, o.letter, e.letter
from (
select id, letter, id as base from my_table where id % 2 = 0
) o right join (
select id, letter, (id - 1) as base from my_table where id % 2 <> 0
) e on e.base = o.base
) x
order by base
Just use conditional aggregation:
select max(case when id % 2 = 0 then letter end) as col1,
max(case when id % 2 = 1 then letter end) as col2
from t
group by floor(id / 2);
If you prefer, you can use mod() instead of %. MySQL supports both.

How to combine data from one table where there are duplicate values into a single row?

I have tried what i thought was a pretty simple sql with php to do the following but it is not turning out correctly and i cant find a good way to "google" the solutions. I have a table valoreguide2 that holds over 200,000 records with multiple columns in this table are duplicate rows that have different values in some columns but same value in other columns. I want to take all of the values and put them in a new table, while doing this i want to combine the rows that have the same value in the column labeled isbn and keep all of the values for those rows in one row in the new table.
example is
if you cant see the image it is a table with 20 columns including a auto increment field. I would like to take all of the information from this table and insert it into another table with different column titles but combine them based on isbn. the code i have written is a follows:
`$results = $conn->query("select * from valoreguide2 group by isbn");
while ($row12 = $results->fetch_assoc()) {
$isbn = $row12['isbn'];
$APrice =$row12['Acomm'];
$AQty=$row12['Aqty'];
$IPrice =$row12['Icomm'];
$IQty=$row12['Iqty'];
$SPrice =$row12['Scomm'];
$SQty=$row12['Sqty'];
$TPrice =$row12['Tcomm'];
$TQty=$row12['Tqty'];
$NPrice =$row12['Ncomm'];
$NQty=$row12['Nqty'];
$BBPrice =$row12['BBcomm'];
$BBQty=$row12['BBqty'];
$guide_prices = array('amtext'=>(float)($APrice), 'ingram'=>(float)($IPrice), 'sterling'=>(float)($SPrice), 'tichenor'=>(float)($TPrice), 'nebraska'=>(float)($NPrice), 'BB'=>(float)($BBPrice), );
$bestGuidePrice = max($guide_prices);
$bestGuidePrice = number_format($bestGuidePrice,2,'.','');
foreach ($guide_prices as $key => $val) {
if ($val == max($guide_prices))
{
$bestGuide = $key;
}
}
$valoreprice=(($bestGuidePrice/1.15)-5);
$conn->query("insert into valorebest2 (isbn, aprice, iprice, sprice, tprice, nprice, bookbyte, bestprice, valore, bestguide) values ('$isbn','$APrice','$IPrice','$SPrice','$TPrice','$NPrice','$BBPrice','$bestGuidePrice','$valoreprice','$bestGuide') ");
}`
but the result is not combining the rows it is just picking one.. If i have not provided enough please let me know.. i did not want to type on and on when someone is going to say hey you missed a comma.
Edited:
Using MySQL
Edited: This is the output i am looking for
Can you be specific about the database, you use: Oracle, MS SQL, MySql ..?
Here is an answer that it based on ansi SQL. Hope it helps
Testdata.
CREATE TABLE tbs_test (ID, ISBN, A, B, C, D) AS
SELECT 1,'0001','A','B','C',10 FROM DUAL UNION ALL
SELECT 2,'0002','A',null,null,null FROM DUAL UNION ALL
SELECT 3,'0002',null,'B',null,null FROM DUAL UNION ALL
SELECT 4,'0002',null,null,'C',null FROM DUAL UNION ALL
SELECT 5,'0003','A',null,'C',10 FROM DUAL UNION ALL
SELECT 6,'0003',null,null,null,10 FROM DUAL UNION ALL
SELECT 7,'0004',null,null,'C',10 FROM DUAL;
This select groups by isbn, taking the min-value of each column, that resides in a row with the same isbn.
select isbn, min(A), min(B), min(C), min(D)
from tbs_test
group by isbn
order by isbn;
This select groups by isbn, takes min-value of A,B,C and sums D
select isbn, min(A), min(B), min(C), sum(D)
from tbs_test
group by isbn
order by isbn;
Hope this helps :-)
If it wont let you select, how on earth can you get any values to work with? :-)
It you'll succeed in getting acces to the data, this would do it (notice: the fake_time column is just a way to emulate two different situations in the input table. You can remove it from the select/update if you'll go live with the code):
CREATE TABLE tbs_test_input (ID, ISBN, A, B, C, D, Fake_time) AS
SELECT 1,'0001','A','B','C',10,1 FROM DUAL UNION ALL
SELECT 2,'0002','A',null,null,null,1 FROM DUAL UNION ALL
SELECT 3,'0002',null,'B',null,null,1 FROM DUAL UNION ALL
SELECT 4,'0002',null,null,'C',null,1 FROM DUAL UNION ALL
SELECT 5,'0003','A',null,'C',10,1 FROM DUAL UNION ALL
SELECT 6,'0003',null,null,null,10,1 FROM DUAL UNION ALL
SELECT 7,'0004',null,null,'C',10,1 FROM DUAL UNION ALL
SELECT 8,'0003',null,'B',null,null,2 FROM DUAL UNION ALL
SELECT 9,'0003',null,'B',null,20,2 FROM DUAL UNION ALL
SELECT 10,'0004','A',null,null,null,2 FROM DUAL
;
create table tbs_test_output as select ISBN, A, B, C, D
from tbs_test_input where 1=2;
insert into tbs_test_output
select isbn, min(A), min(B), min(C), min(D)
from tbs_test_input
where isbn not in (select isbn from tbs_test_output)
and fake_time = 1
group by isbn
order by isbn;
select * from tbs_test_output;
update tbs_test_output o
set (A,B,C,D) = (
select min(i.A), min(i.B), min(i.C), min(i.D)
from tbs_test_input i
where i.fake_time = 2
group by i.isbn
having i.isbn = o.isbn
)
WHERE EXISTS (
SELECT 1
FROM tbs_test_input i
WHERE i.isbn = o.isbn
and i.fake_time = 2)
;
select * from tbs_test_output;
The result:
4 rows inserted.
ISBN A B C D
\---- - - - ----------
0001 A B C 10
0002 A B C
0003 A C 10
0004 C 10
2 rows updated.
ISBN A B C D
\---- - - - ----------
0001 A B C 10
0002 A B C
0003 B 20
0004 A

SQL group by where values are same within group

So, I have a table with which individuals (person_id) have multiple lines (up to 4) and values for a column (value_column) can either = 0 or 1
I'd like to write a piece of code that returns a row for each person_id in which their value for value_column is only 0 or only 1 (even though they may have 3 or 4 rows each)
It's probably an easy line of code, but for someone with less SQL experience, it seems nearly impossible!
EDIT: here is a quick sample of lines:
person_id value_column
A 0
A 1
A 0
B 0
B 0
B 0
B 0
C 1
C 1
C 1
And I would expect the line of code to return the folowing:
person_id value_column
B 0
C 1
You can try something like this probably
select distinct * from table1
where person_id in
( select person_id
from table1
group by person_id
having count(distinct value_column) <= 1
)
Inner query, will return only those person_id for which there is only one value_column present and that's the same thing getting done by count(distinct value_column) <= 1 and then outer query just selects everything for those person_id.
select * from myTable where person_id not in
(select a.person_id from myTable a, myTable b
where a.person_id = b.person_id
and a.value_column <> b.value_column)
Get persons with different values and then get those who are not in this first query.
Or quicker and nicer :
select person_id, min(value_column)
from myTable
group by person_id
having min(value_column)=max(value_column)

repeat result multiple times in mysql

I have a table having id and no field, what I really want is the result raw will be repeated no filed times, if the no field is 2 then that raw must be repeated twice in result.
this is my sample table structure:
id no
1 3
2 2
3 1
now I need to get a result like:
1 3
1 3
1 3
2 2
2 2
3 1
I tried to write mysql query to get the result like above, but failed.
You need a table of numbers to accomplish this. For just three values, this is easy:
select t.id, t.no
from t join
(select 1 as n union all select 2 union all select 3
) n
on t.no <= n.no;
This query must do what you want to achieve:
select t.id, t.no from test t cross join test y where t.id>=y.id
not completely solve your problem, but this one can help
set #i=0;
select
test_table.*
from
test_table
join
(select
#i:=#i+1 as i
from
any_table_with_number_of_rows_greater_than_max_no_of_test_table
where
#i < (select max(no) from test_table)) tmp on no >= i
order by
id desc
EDIT :
This is on SQL Server. I checked online and see that CTEs work on MySQL too. Just couldn't get them to work on SQLFiddle
Try this, remove unwanted columns
create table #temp (id int, no int)
insert into #temp values (1, 2),(2, 3),(3, 5)
select * from #temp
;with cte as
(
select id, no, no-1 nom from #temp
union all
select c.id, c.no, c.nom-1 from cte c inner join #temp t on t.id = c.id and c.nom < t.no and c.nom > 0
)
select * from cte order by 1
drop table #temp

path enumeration using prime numbers(insert child)

I need a little help,
I have a table tree which has following data:
id | person | prime | product
----+--------+-------+---------
1 x 2 2
2 z 3 6
4 d 5 30
How this works is
Prime and products are used to calculate the parent child relationship of my family.
Prime = next available prime number
Product = (prime * product of parent). Each product of primes can only be divided by those primes.
for person d parent is z since 5(prime of d) * 6 (productof z) = 30(product of d)
Using the same principle I have to write a singe query to insert child of d (say a,b,c) to the table.
Provided there is another table prime_numbers with column primes which holds the list of prime numbers (2,3,5,7,11,13,17,....)
I had consulted This.
But was unable to derive the solution from it.
I don't have mySql installed so I can't check this, but maybe it can be a start.
You can use an Insert-select based on a join of some subqueries:
a subquery for getting a list of next prime numbers
from your_table, get the father (id=4)
join of 1 + 2 for calculating next pruducts and adding row number
a subquery for the new persons (I unioned constants) with row number
join of 3 + 4 according to row number
So it may look like:
SELECT prsns.idd, prsns.namee, t1.nxt, t1.product
FROM
(SELECT #rownum:=#rownum+1 'rn', p.nxt prime, p.nxt * tt.product product
(SELECT cur, max(nxt) as nxt
FROM
( select t.prime as cur, nxtt.prime as nxt
from prime_numbers t, prime_numbers nxtt
where t.prime > nxtt.prime )
GROUP BY cur
ORDER BY nxt) p, your_table tt, (SELECT #rownum:=0) r
WHERE tt.id = 4
AND p.nxt > tt.prime) t1,
(
SELECT #rownum:=#rownum+1 'rn', idd, namee
FROM (SELECT #rownum:=0) r, (
select 5 as idd, 'a' as namee union
select 6 , 'b' union
select 7 , 'c' union
)
) prsns
WHERE prsns.rn = t1.rn