mysql join and insert statement - mysql

I created a view using left join to see the number of duplicate ip.
In this view
SELECT
a.id,
b.id,
COUNT (b.id),
a.ip
FROM
`VIEW` AS a
LEFT JOIN
`VIEW` AS b on a.ip = b.ip
WHERE
a.id = 298
GROUP BY
b.id;
When i execute this query, i get the data i want for one id.
However, if i check the number of duplicate ip's in the whole id
and execute the following query to store it in the table.
INSERT
INTO
TABLE
SELECT
a.id,
b.id,
COUNT (b.id),
a.ip
FROM
`VIEW` AS a
LEFT JOIN
`VIEW` AS a.ip = b.ip
WHERE
a.id IN
(
SELECT DISTINCT
id
FROM
`VIEW`)
GROUP BY
b.id;
Other values come out.
The first query statement works fine and the second query statement shows an invalid value.
How can I use the second query statement to get the result of the first query statement?

Use GROUP BY a.id, b.id so that you get a separate count for each a.id that you join with.
There's also no reason to use LEFT JOIN here. Since you're joining the view with itself, there will always be a matching row. Just use a normal INNER JOIN.
The WHERE clause is totally ineffective. How can the id not be in the list of distinct id's from the same view? Get rid of that clause.
You also have a syntax error:
JOIN `VIEW` AS a.ip = b.ip
should be:
JOIN `VIEW` AS b ON a.ip = b.ip
The correct query should be:
INSERT
INTO
TABLE
SELECT
a.id,
b.id,
COUNT(*),
a.ip
FROM
`VIEW` AS a
JOIN
`VIEW` AS b ON a.ip = b.ip
GROUP BY
a.id, b.id;

Related

SQL alternative for fetching latest record of each item in a table using partition

Im have been query the database to collectively fetch latest record or each item using PARTITION and ROW_COUNT() which works on MariaDB version 10.4* but i want to query the same on a MySQL version 5.7* database but it doesn't work there. I would like to figure out the alternative that will work on the MySQL database. Kindly help me out.
The query is as follows.
SELECT A_id, B_id, Created_at
FROM
(
SELECT a.id as A_id, b.id as B_id, b.Created_at,
ROW_NUMBER() OVER (PARTITION BY a.id ORDER BY b.Created_at DESC) AS rn
FROM beta b
JOIN alpha a ON b.a_id = a.id
) q
WHERE rn = 1
You may use a join to subquery which finds the latest record for each id:
SELECT a.id AS A_id, b.id AS B_id, b.Created_at
FROM alpha a
INNER JOIN beta b
ON a.id = b.a_id
INNER JOIN
(
SELECT a.id AS max_id, MAX(b.Created_at) AS max_created_at
FROM alpha a
INNER JOIN beta b ON a.id = b.a_id
GROUP BY a.id
) t
ON t.max_id = a.id AND t.max_created_at = b.Created_at;
The idea here is that the additional join to the subquery above aliased as t will only retain the record, for each a.id, having the latest Created_at value from the B table. This has the same effect as your current approach using ROW_NUMBER, without actually needing to use analytic functions.

How to use GROUP_CONCAT on multiple JOIN

I am currently retrieving data from multiple tables using a cus_id as the initial query. From here I have multiple tables that can have various rows of data that I would like to retrieve and use GROUP_CONCAT to return this data in a single row. At the moment, my query is returning duplicate data based on the max number of rows returned by one of the group concats.
SELECT a.id,c.x,c.y,c.z
GROUP_CONCAT(a.column_a) AS aca,
GROUP_CONCAT(a.column_b) AS acb,
GROUP_CONCAT(b.column_a) AS bca,
GROUP_CONCAT(b.column_b) AS bcb,
FROM `table_a` a
INNER JOIN `table_b` b ON a.id = b.id
INNER JOIN `table_c` c ON a.id = c.id
WHERE a.id = ?
Also, in this scenario, what is the correct join method to use. I am expecting all the fields I am requesting to have some sort of data.
Problem was resolved by using sub queries to isolate the GROUP_CONCAT requests. This allowed me to get only the data I wanted without duplicate results manipulated by other JOIN requests.
SELECT a.id,c.x,c.y,c.z
(SELECT GROUP_CONCAT(column_a) FROM table_a) AS aca,
(SELECT GROUP_CONCAT(column_b) FROM table_a) AS acb,
(SELECT GROUP_CONCAT(column_a) FROM table_b) AS bca,
(SELECT GROUP_CONCAT(column_b) FROM table_b) AS bcb,
FROM table_a a
INNER JOIN `table_c` c ON a.id = c.id
WHERE a.id = ?
Aggregate before joining. Somthing along the lines of:
select
a.*,
b.grp_a,
b.grp_b,
c.grp_x,
b.grp_y
from table_a a
join
(
select
a_id,
group_concat(a order by b_id) as grp_a,
group_concat(b order by b_id) as grp_b
from table_b
group by a_id
) b on b.a_id = a.id
join
(
select
a_id,
group_concat(x order by c_id) as grp_x,
group_concat(y order by c_id) as grp_y
from table_c
group by a_id
) c on c.a_id = a.a_id
order by a.a_id;

Does COALESCE work properly with VIEWs?

I have my view definition:
CREATE VIEW `view` AS
SELECT a.id,
COALESCE(COALESCE(b.name, c.name), a.name) AS name
FROM a_table a
LEFT JOIN b_table b on a.b_id = b.id
LEFT JOIN c_table c on a.c_id = c.id
And after I'm updating a_table row with new name it doesn't get updated in my view. But if I change name to COALESCE(a.name, COALESCE(b.name, c.name)) AS name it works.
As I understand the reason is in COALESCE. It takes the first not null value and in my case it's b.name and gets updated only when b.name is updated.
Is there any option to updated the view when any of COALESCE values are changed?
COALESCE() works fine in views. It also takes multiple arguments, so I would suggest writing this as:
CREATE VIEW `view` AS
SELECT a.id, COALESCE(b.name, c.name, a.name) AS name
FROM a_table a LEFT JOIN
b_table b
ON a.b_id = b.id LEFT JOIN
c_table c
ON a.c_id = c.id;
Views are not "updated". They are SQL code that is plugged into queries when the view is reference. The data comes from the underlying tables.

mysql display field values from subquery

I have following query that works correctly:
select * from myTable a where a.company is null and exists (select b.company from myTable b where b.id = a.id and b.office_id = a.office_id and b.company is not null);
Now, I also want to display the field value b.company from the subquery next to the fields from myTable a.
How do I get this done?
Thank you and best regards
If you want results from multiple tables you should join the tables together.
Since you want only records from A that exist in B, you need to use an outer JOIN returning all records from A and only those matching in B. But then you want to exclude all those records from A that were not found in B.
SELECT *, b.company
FROM myTable a
LEFT JOIN myTable B
ON b.id = a.id
and b.office_id = a.office_id
and b.company_ID is not null
WHERE a.company is null
and B.ID is not null and B.office_ID is not null --this handles the exists part.

Aggregating strings across `group by` in SQL?

Consider the following schema:
create table A
(
id int primary id
)
create table B
(
a_id int,
s varchar(255)
)
And then the following query:
select A.id, sum(1), ??? concat_join(B.s) ???
from A left join B on A.id = B.a_id group by A.id
There is a 1-to-many relation between A and B, so multiple rows will be grouped into one. The desired behaviour of "concat_join" would be for each B.s in the group join them together into a single string by concatenating them (perhaps with a space seperator).
Is there someway to express this is MySQL 5.5?
use GROUP_CONCAT
select A.id, sum(1), GROUP_CONCAT(B.s)
from A left join B on A.id = B.a_id
group by A.id
by default, the string is separated by a comma. if you want to change it, add SEPARATOR keyword,
select A.id, sum(1), GROUP_CONCAT(B.s SEPARATOR ';')
from A left join B on A.id = B.a_id
group by A.id
SQLFiddle Demo