Query with intermediate table in MySQL - php

I'm trying to make a query with an intermediate table with very important data (field called "quantity") and I can't show all the data that I need
The tables are
TP_PANTONE_COLORS
id_pantone_color (primary key)
name_pantone_color
hex_pantone_color
TP_COLOR_CART
id_color_cart (primary key)
name_color_cart
description
link
TP_PANTONE_BASE (intermediate)
id_quantity (primary key)
id_pantone_color
id_color_cart
quantity
I need a table like this
NAME_PANTONE_COLOR | NAME_COLOR_CART | QUANTITY | LINK
I'm trying with
SELECT * FROM tp_color_cart A
INNER JOIN tp_pantone_base B ON
A.id_color_cart = B.id_color_cart
INNER JOIN tp_pantone_colors C ON
C.id_pantone_color = B.id_pantone_color
WHERE id_pantone_color=1
and
SELECT
A.name_pantone_color AS 'NAME_PANTONE_COLOR' ,
C.name_color_cart AS 'NAME_COLOR_CART',
B.quantity AS 'QUANTITY',
C.link AS 'LINK'
FROM tp_pantone_colors A
JOIN tp_pantone_base B ON B.id_pantone_color=A.id_pantone_color
INNER JOIN tp_color_cart C ON B.id_color_cart=C.id_color_cart
WHERE A.id_pantone_color=1
but this queries returns one row and TP_PANTONE_BASE have 4 rows with id_pantone_color=1

I cannot reproduce your problem. Given the appropriate data I would expect your query to return 4 rows even if there was only 1 record in TP_PANTONE_BASE and tp_color_cart
for example
drop table if exists tp_pantone_colors,TP_PANTONE_BASE,TP_COLOR_CART;
create table TP_PANTONE_COLORS(
id_pantone_color int,
name_pantone_color varchar(1),
hex_pantone_color int
);
insert into TP_PANTONE_COLORS values
(1,'a',1),(1,'a',1),(1,'a',1),(1,'a',1);
create table TP_COLOR_CART(
id_color_cart int,
name_color_cart varchar(1),
description varchar(2),
link int
);
insert into tp_color_cart values
(1,'b','bb',1);
create table TP_PANTONE_BASE (
id_quantity int,
id_pantone_color int,
id_color_cart int,
quantity int
);
insert into TP_PANTONE_BASE values
(1,1,1,10);
select A.name_pantone_color AS 'NAME_PANTONE_COLOR' ,
C.name_color_cart AS 'NAME_COLOR_CART',
B.quantity AS 'QUANTITY',
C.link AS 'LINK'
from tp_pantone_colors a
join TP_PANTONE_BASE b on b.id_pantone_color = a.id_pantone_color
join TP_COLOR_CART c on c.id_color_cart = b.id_color_cart;
+--------------------+-----------------+----------+------+
| NAME_PANTONE_COLOR | NAME_COLOR_CART | QUANTITY | LINK |
+--------------------+-----------------+----------+------+
| a | b | 10 | 1 |
| a | b | 10 | 1 |
| a | b | 10 | 1 |
| a | b | 10 | 1 |
+--------------------+-----------------+----------+------+
4 rows in set (0.00 sec)
In other words we cannot solve this without sample data from you.
Based on your data
SELECT A.id_pantone_color,b.*
from tp_pantone_colors a
join TP_PANTONE_BASE b on b.id_pantone_color = a.id_pantone_color
WHERE A.id_pantone_color=1;
+------------------+-------------+------------------+---------------+----------+
| id_pantone_color | id_quantity | id_pantone_color | id_color_cart | quantity |
+------------------+-------------+------------------+---------------+----------+
| 1 | 1 | 1 | 30 | 13,693 |
| 1 | 2247 | 1 | 452 | 13,543 |
| 1 | 5616 | 1 | 453 | 2,55 |
| 1 | 7862 | 1 | 455 | 70,215 |
+------------------+-------------+------------------+---------------+----------+
4 rows in set (0.00 sec)
select * from TP_COLOR_CART where id_color_cart in(30,452,453,455)
+---------------+-----------------+-------------+---------+------+
| id_color_cart | name_color_cart | description | color | link |
+---------------+-----------------+-------------+---------+------+
| 30 | 001 | White | #FFFFFF | # |
+---------------+-----------------+-------------+---------+------+
1 row in set (0.00 sec)
If you want you could
select A.name_pantone_color AS 'NAME_PANTONE_COLOR' ,
C.name_color_cart AS 'NAME_COLOR_CART',
B.quantity AS 'QUANTITY',
C.link AS 'LINK'
from tp_pantone_colors a
join TP_PANTONE_BASE b on b.id_pantone_color = a.id_pantone_color
left join TP_COLOR_CART c on c.id_color_cart = b.id_color_cart
WHERE A.id_pantone_color=1;
+--------------------+-----------------+----------+------+
| NAME_PANTONE_COLOR | NAME_COLOR_CART | QUANTITY | LINK |
+--------------------+-----------------+----------+------+
| PANTONE 1605 C | 001 | 13,693 | # |
| PANTONE 1605 C | NULL | 13,543 | NULL |
| PANTONE 1605 C | NULL | 2,55 | NULL |
| PANTONE 1605 C | NULL | 70,215 | NULL |
+--------------------+-----------------+----------+------+
4 rows in set (0.02 sec)
But it's not your query that's wrong it's the data.

Related

Query Select and Show All First Table And Second Table Even is not Exist in Second Table

SAMPLE TABLE
TABLE FIRST_TABLE
| rid | requirements |
| 1 | 2x2 pic |
| 2 | valid id |
| 3 | 137 form |
| 4 | app form |
Second table
| id | applicant_id | rid | remarks |
| 1 | 1 | 1 | pass |
| 2 | 1 | 2 | pass |
| 3 | 2 | 1 | pass |
How to select all records from first table and show even the data is not exist on second table.
Result should be like this.
applicant_id | rid | remarks |
1 | 1 | pass |
1 | 2 | pass |
1 | 3 | null |
1 | 4 | null |
this is my sample code.
select requirements from first_table
left join second_table on first_table.rid = second_table.rid
where second_table.applicant_id = 1
group by first_table.rid
//result :
applicant_id | rid | remarks |
1 | 1 | pass |
1 | 2 | pass |
You just need to move the second_table.applicant_id = 1 to the join.
select requirements, first_table.rid, remarks
from first_table
left join second_table on
first_table.rid = second_table.rid and
second_table.applicant_id = 1
group by first_table.rid
http://sqlfiddle.com/#!9/a0cffdd/17

How to select similar values together in same query?

I have the database as below, i need to get all the zeros and ones in separate list from the below table, that is to get all the zero together in a column and all the ones together in separate column
database
| id | value |
-------------
| 1 | 0 |
| 2 | 1 |
| 3 | 0 |
| 4 | 1 |
expected result
| sp.id | stop | st.id | start|
-------------------------------
| 1 | 0 | 2 | 1 |
| 3 | 0 | 4 | 1 |
or
| id | value |
-------------
| 1 | 0 |
| 3 | 0 |
| id | value |
-------------
| 2 | 1 |
| 4 | 1 |
SELECT a.id AS sp.id, a.value AS stop, b.id AS st.id, b.value AS start
FROM (SELECT * FROM TABLE WHERE = 0) a
LEFT JOIN (SELECT * FROM TABLE WHERE = 1) b
ON a.id = b.id
UNION
SELECT a.id AS sp.id, a.value AS stop, b.id AS st.id, b.value AS start
FROM (SELECT * FROM TABLE WHERE = 0) a
RIGHT JOIN (SELECT * FROM TABLE WHERE = 1) b
ON a.id = b.id
For your expected result 1, you can use case
select case when value=0 then id end as spid,
case when value=0 then value end as stop,
case when value=1 then id end as stid,
case when value=1 then value end as start
from yourtable.
But you will get NULL for empty rows as shown below. If that is fine, you can use the above query. If it is a String you can use MAX() or MIN() with group by to avoid this empty values.
OUTPUT
+------+------+------+-------+
| spid | stop | stid | start |
+------+------+------+-------+
| 1 | 0 | | |
+------+------+------+-------+
| | | 2 | 1 |
+------+------+------+-------+
| 3 | 0 | | |
+------+------+------+-------+
| | | 4 | 1 |
+------+------+------+-------+
For you expected output 2, you can directly use UNION ALL
select id,value from test where value=0
union all
select id,value from test where value=1
OUTPUT
+----+-------+
| id | value |
+----+-------+
| 1 | 0 |
+----+-------+
| 3 | 0 |
+----+-------+
| 2 | 1 |
+----+-------+
| 4 | 1 |
+----+-------+
CHECK DEMO HERE

How to get distinct count of many fields in one row using best possible method

I have 2 tables in my demos database, in which I join them based on 2 keys, here I would like to count distinct of matched result,
my first table
MariaDB [demos]> select * from main_info;
+------+------+-------+-------+----------+
| key1 | key2 | info1 | info2 | date |
+------+------+-------+-------+----------+
| 1 | 1 | 15 | 90 | 20120501 |
| 1 | 2 | 14 | 92 | 20120601 |
| 1 | 3 | 15 | 82 | 20120801 |
| 2 | 1 | 17 | 90 | 20130302 |
| 2 | 2 | 16 | 88 | 20130601 |
+------+------+-------+-------+----------+
5 rows in set (0.00 sec)
And my second table
MariaDB [demos]> select * from product1;
+------+------+--------+--------------+
| key1 | key2 | serial | product_data |
+------+------+--------+--------------+
| 1 | 1 | 0 | NaN |
| 1 | 1 | 1 | NaN |
| 1 | 1 | 2 | NaN |
| 1 | 1 | 3 | NaN |
| 1 | 2 | 0 | 12.556 |
| 1 | 2 | 1 | 13.335 |
| 1 | 3 | 1 | NaN |
| 1 | 3 | 2 | 13.556 |
| 1 | 3 | 3 | 14.556 |
| 2 | 1 | 0 | 12.556 |
| 2 | 1 | 1 | 13.553 |
| 2 | 1 | 2 | NaN |
+------+------+--------+--------------+
12 rows in set (0.00 sec)
So distinct count of field serial is as follows, where serial is not zero
MariaDB [demos]> select count(distinct a.key1,a.key2) as serial_count from main_info a,product1 b where a.key1=b.key1 and a.key2=b.key2 and b.serial !=0;
+--------------+
| serial_count |
+--------------+
| 4 |
+--------------+
1 row in set (0.00 sec)
and distinct count of field product_data is as follows where product_data is not NaN
MariaDB [demos]> select count(distinct a.key1,a.key2) as product_count from main_info a,product1 b where a.key1=b.key1 and a.key2=b.key2 and b.product_data !='NaN';
+---------------+
| product_count |
+---------------+
| 3 |
+---------------+
1 row in set (0.00 sec)
In my original application I have many columns in my table, finally I would like to get result like below using single query, at present I am doing multiple query using PHP which is taking long time because for example if I have 100 columns, I have to execute function 100 times like above, so please someone guide me to speed up my application
+--------------+---------------+
| serial_count |product_count |
+--------------+---------------+
| 4 | 3 |
+--------------+---------------+
Below is structure of tables
DROP TABLE IF EXISTS `main_info`;
CREATE TABLE `main_info` (
`key1` int(11) NOT NULL,
`key2` int(11) NOT NULL,
`info1` int(11) NOT NULL,
`info2` int(11) NOT NULL,
`date` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
LOCK TABLES `main_info` WRITE;
INSERT INTO `main_info` VALUES (1,1,15,90,20120501),(1,2,14,92,20120601),(1,3,15,82,20120801),(2,1,17,90,20130302),(2,2,16,88,20130601);
UNLOCK TABLES;
DROP TABLE IF EXISTS `product1`;
CREATE TABLE `product1` (
`key1` int(11) NOT NULL,
`key2` int(11) NOT NULL,
`serial` int(11) NOT NULL,
`product_data` varchar(1000) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
LOCK TABLES `product1` WRITE;
INSERT INTO `product1` VALUES (1,1,0,'NaN'),(1,1,1,'NaN'),(1,1,2,'NaN'),(1,1,3,'NaN'),(1,2,0,'12.556'),(1,2,1,'13.335'),(1,3,1,'NaN'),(1,3,2,'13.556'),(1,3,3,'14.556'),(2,1,0,'12.556'),(2,1,1,'13.553'),(2,1,2,'NaN');
UNLOCK TABLES;
I didn't understand this why datetype changed, if I run on terminal
$ mysql -u root -p demos -e 'select key1,if(key1 !=0,key1,999.999) as `test1` from main_info'
Enter password:
+------+-------+
| key1 | test1 |
+------+-------+
| 1 | 1.000 |
| 1 | 1.000 |
| 1 | 1.000 |
| 2 | 2.000 |
| 2 | 2.000 |
+------+-------+
I expect it should be integer if IF condition is true
You can do it in a single query using conditional aggregation:
select count(distinct if(b.product_data !='NaN',a.key1, null),
if(b.product_data !='NaN',a.key2, null)) as product_count,
count(distinct if(b.serial !=0,a.key1, null),
if(b.serial !=0,a.key2, null)) as serial_count
from main_info a
inner join product1 b on a.key1=b.key1 and a.key2=b.key2
Output:
product_count serial_count
-----------------------------
3 4
Demo here
Edit: Credit goes to #Paul Spiegel
The query can be simplified using CONCAT:
select count(distinct if(b.product_data !='NaN',
CONCAT(a.key1, ',', a.key2),
null)) as product_count,
count(distinct if(b.serial !=0,
CONCAT(a.key1, ',', a.key2),
null)) as serial_count
from main_info a
inner join product1 b on a.key1=b.key1 and a.key2=b.key2

Sql sum() columns from different tables

Category Table
mysql> SELECT * FROM cats;
+------+------+-----------+
| c_id | p_id | c_name |
+------+------+-----------+
| 1 | 1 | cats 1 |
| 2 | 1 | cats 2 |
| 3 | 1 | cats 3 |
+------+------+-----------+
Meta Table
mysql> SELECT * FROM meta;
+------+------+------+---------+-------------+-------+
| m_id | p_id | c_id | name | description | costs |
+------+------+------+---------+-------------+-------+
| 1 | 1 | 1 | Abhijit | description | 100 |
| 2 | 1 | 1 | Abhijit | description | 200 |
| 3 | 1 | 2 | Abhiji2 | description | 500 |
+------+------+------+---------+-------------+-------+
Transaction Table
mysql> SELECT * FROM transactions;
+------+------+------+---------------------+--------+
| t_id | p_id | m_id | date | amount |
+------+------+------+---------------------+--------+
| 1 | 1 | 1 | 2016-02-16 11:17:06 | 50 |
| 2 | 1 | 1 | 2016-02-16 11:17:06 | 50 |
| 3 | 1 | 2 | 2016-02-16 11:17:06 | 50 |
| 4 | 1 | 2 | 2016-02-16 11:17:06 | 150 |
+------+------+------+---------------------+--------+
I want to sum() for each category costs (from meta table) and amount( from transaction table).
I use:
mysql> SELECT c.*, SUM(t.amount), SUM(m.costs)
FROM cats c
LEFT JOIN meta m ON m.c_id=c.c_id
LEFT JOIN transactions t ON t.m_id=m.m_id
GROUP BY c.c_id;
+------+------+-----------+--------+---------------+--------------+
| c_id | p_id | c_name | add_by | SUM(t.amount) | SUM(m.costs) |
+------+------+-----------+--------+---------------+--------------+
| 1 | 1 | Abhijit | 1 | 100 | 400 |
| 2 | 1 | Abhiji2 | 1 | 200 | 500 |
+------+------+-----------+--------+---------------+--------------+
It's wrong. The Costs of cats id 1 is 300 but here I got 400
I Want Get Return From Query Like This:
+------+------+-----------+--------+---------------+--------------+
| c_id | p_id | c_name | add_by | SUM(t.amount) | SUM(m.costs) |
+------+------+-----------+--------+---------------+--------------+
| 1 | 1 | Abhijit | 1 | 100 | 300 |
| 2 | 1 | Abhiji2 | 1 | 200 | 500 |
+------+------+-----------+--------+---------------+--------------+
I think you had a typo (or error) in one of your JOIN conditions. I think you intended your original query to be this:
SELECT c.*, SUM(t.amount), SUM(m.costs)
FROM cats c
LEFT JOIN meta m ON m.c_id = c.c_id
LEFT JOIN transactions t ON t.m_id = m.c_id
GROUP BY c.c_id;
Note carefully ON t.m_id = m.c_id, which agrees with your expected output. In any case, I reworked your query as follows:
SELECT c.c_id, c.p_id, c.c_name, t2.transactionCosts, t1.metaCosts
FROM cats c
LEFT JOIN
(
SELECT c_id, SUM(costs) AS metaCosts
FROM meta
GROUP BY c_id
) t1
ON c.c_id = t1.c_id
LEFT JOIN
(
SELECT m_id, SUM(amount) AS transactionCosts
FROM transactions
GROUP BY m_id
) t2
ON c.c_id = t2.m_id
WHERE t2.transactionCosts IS NOT NULL OR t1.metaCosts IS NOT NULL;
The first subquery computes the meta total for each c_id, and the second subquery computes the transaction total for each m_id. These results are then both joined together with the cats table to get your final result.
Follow the link below for a running demo:
SQLFiddle
the problem is you select c.* but only group by c_id, in this case you have 2 options. window function or subquery.
via over(partition by):
SELECT c.*,
SUM(t.amount)over(partition by c.c_id) as amount,
SUM(m.costs)over(partition by c.c_id) as cost
FROM con_cats c
LEFT JOIN meta m ON m.c_id=c.c_id
LEFT JOIN transactions t ON t.m_id=m.m_id;
via subquery:
select a.*,b.amount,b.costs from con_cats a
inner join
(SELECT c.c_id, SUM(t.amount) as amount, SUM(m.costs) as costs
FROM con_cats c
LEFT JOIN meta m ON m.c_id=c.c_id
LEFT JOIN transactions t ON t.m_id=m.m_id
GROUP BY c.c_id) b
on a.c_id = b.c_id;

Count the frequency of votes in MySQL

I am making a website where users can vote on which category a page is. They can vote that the page is in category a, b, c, or d.
I need to find the most commonly occurring category in the MySQL row out of all the votes.
Each time a user submits their vote, it submits the "category" that they voted for, and the "page_id".
I have this so far:
SELECT page_id, category
FROM categories
GROUP BY page_id
I cannot use a COUNT(*) WHERE category = 'a' then repeat it for each category because there is many more categories in the actual project.
If your table looks something like this:
SELECT * from categories;
+---------+----------+
| page_id | category |
+---------+----------+
| 1 | a |
| 1 | b |
| 1 | a |
| 1 | c |
| 1 | a |
| 1 | b |
| 1 | a |
| 2 | d |
| 2 | d |
| 2 | c |
| 2 | d |
| 3 | a |
| 3 | b |
| 3 | c |
| 4 | c |
| 4 | d |
| 4 | c |
+---------+----------+
17 rows in set (0.00 sec)
Then you may want to try this query:
SELECT c1.page_id, MAX(freq.total),
(
SELECT c2.category
FROM categories c2
WHERE c2.page_id = c1.page_id
GROUP BY c2.category
HAVING COUNT(*) = MAX(freq.total)
LIMIT 1
) AS category
FROM categories c1
JOIN (
SELECT page_id, category, count(*) total
FROM categories
GROUP BY page_id, category
) freq ON (freq.page_id = c1.page_id)
GROUP BY c1.page_id;
Which returns this:
+---------+-----------------+----------+
| page_id | MAX(freq.total) | category |
+---------+-----------------+----------+
| 1 | 4 | a |
| 2 | 3 | d |
| 3 | 1 | a |
| 4 | 2 | c |
+---------+-----------------+----------+
4 rows in set (0.00 sec)
Compare the results with the actual frequency distribution:
SELECT page_id, category, COUNT(*) FROM categories GROUP BY page_id, category;
+---------+----------+----------+
| page_id | category | COUNT(*) |
+---------+----------+----------+
| 1 | a | 4 |
| 1 | b | 2 |
| 1 | c | 1 |
| 2 | c | 1 |
| 2 | d | 3 |
| 3 | a | 1 |
| 3 | b | 1 |
| 3 | c | 1 |
| 4 | c | 2 |
| 4 | d | 1 |
+---------+----------+----------+
10 rows in set (0.00 sec)
Note that for page_id = 3, there is no leading frequency, in which case this query makes no guarantee on which category will be chosen in such a case.
something like
SELECT category, page_id, count(vote_id)
FROM categories
WHERE category in ('a', 'b', 'c', 'd')
GROUP BY category, page_id
ORDER BY count(vote_id) DESC
LIMIT 1
should do the trick. I assume here the votes are individually stored in a separate row per vote.
It only looks in the cqtegory you're interested in, sorts with the most votes first and only returns the first one.

Categories