SQL GROUP_CONCAT alias in WHERE - mysql

Here's my sql statement:
SELECT
tA.a1, GROUP_CONCAT(tB.b2) AS b2
FROM
tableA tA
LEFT JOIN
tableB tB ON tA.a2 = tB.b1
WHERE
CONCAT(tA.a1, b2) LIKE '%somestring%'
GROUP BY tA.a1;
I get an sql error saying something along the lines of "unknown column name b2 in WHERE".

SELECT
tA.a1, GROUP_CONCAT(tB.b2) AS b2
FROM
tableA tA
LEFT JOIN
tableB tB ON tA.a2 = tB.b1
GROUP BY tA.a1
HAVING
CONCAT(tA.a1, b2) LIKE '%somestring%';

You can't use aliases in WHERE clause - but in your case that's even senseless, because WHERE applies filter to rows that will be grouped while GROUP_CONCAT() collects rows that are already grouped
You may do that, for example, with subquery:
SELECT *
FROM
(SELECT
tA.a1 AS ta1, GROUP_CONCAT(tB.b2) AS b2
FROM
tableA tA
LEFT JOIN
tableB tB ON tA.a2 = tB.b1
GROUP BY tA.a1) AS grouped
WHERE
CONCAT(ta1, grouped.b2) LIKE '%somestring%'

for filtering aggregate functions, use HAVING instead of WHERE
select a, group_concat(b) as b_aggregate from
tbl
where concat(a,b) like "%somestring%" -- not aggregate
group by a
having concat(a, group_concat(b)) like "%somestring%" -- aggregate

Related

How to filter out duplicates from a union query?

I have two similar SELECT queries that retrieve data from the same table "my_table".
-- 1st select
SELECT
my_table.id,
a,
b
FROM my_table
JOIN table2 ON u = v
JOIN table3 ON x = y
UNION ALL
-- 2st select
SELECT
my_table.id,
a,
b
FROM my_table
JOIN table2 ON r = s
JOIN table3 ON t = u
Duplicates are to be filtered out under the following conditions:
If the second select returns an id that is already present in the 1st select, it should be discarded.
Is there an easy solution without using a common table expression?
Note: The SQL does not have to be a UNION and can also be changed.
UNION filters out duplicate rows by default. UNION ALL does not remove duplicates.
But the duplicates are based on all columns being identical, not just the id column. If a given id value occurs in both queries, but any of the other two columns are different, then it counts as a distinct row.
If you want to reduce the result to a single row per id, the use a GROUP BY:
SELECT id, ...aggregate expressions...
FROM (
SELECT my_table.id, a, b ...
UNION
SELECT my_table.id, a, b ...
) AS t
GROUP BY id;
When you GROUP BY id, then any other expressions of the outer select-list must be in aggregate functions like MAX() or SUM(), etc.
The reason it is important to use an aggregate function is that when there are multiple rows with the same id value which you want to reduce to one row, what value should be displayed for a and b?
Example:
id
a
b
4
12
24
4
18
28
If you group by id, you would get one row for id=4, but what value for the other two columns?
id
a
b
4
?
?
Read https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html for more details on this. Or my answer to Reason for Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause
You must use an aggregate function, which includes GROUP_CONCAT() to append all the values from that column in a comma-separated list. Or you can use ANY_VALUE() which picks one of the values from that column arbitrarily.
I think this should do it:
-- 1st select
SELECT
my_table.id,
a,
b
FROM my_table
JOIN table2 ON u = v
JOIN table3 ON x = y
WHERE id NOT IN (
SELECT
my_table.id,
FROM my_table
JOIN table2 ON r = s
JOIN table3 ON t = u
)
UNION ALL
-- 2st select
SELECT
my_table.id,
a,
b
FROM my_table
JOIN table2 ON r = s
JOIN table3 ON t = u

How to optimize sql select statement?

I am having an issue with SQL select statement. I am trying to get the percentage using below logic.
For example, I have two tables. One is TableA and another TableB
TableA has column ID, A1, A2.., Get total distinct count of A1 as "X".
TableB has column ID, B1, B2, FK_A1. Get count of B2 as "Y".
Get (Y/X)*100 as Total Percentage.
I was able to do it using subqueries but would like to use a simple and effective statement. Is it possible to get all the above 3 cases in one select statement? Your help would be highly appreciated.
Select
(Select count(distinct A1) from TableA) As C1,
(Select count(B2) from TableB Inner Join TableA ON TableB.FK_A1=TableA.A1)
C2)
Try this query
SELECT ( COUNT(B2) / COUNT(DISTINCT A1) ) * 100 AS TOTAL_PERC FROM TABLEA A INNER JOIN TABLEB B ON TABLEB.FK_A1 = TABLEA.A1;
You can use a simple join between two tables:
SELECT
( COUNT(DISTINCT A1) / COUNT(B2) ) * 100 AS PRCNTG
FROM
TABLEA A
INNER JOIN TABLEB B ON TABLEB.FK_A1 = TABLEA.A1;
apply DISTINCT on B2 if needed in your case.
apply OUTER join if needed in your case.
Cheers!!
You can use inner join with group by to achieve this. You can also use cte to make your distinct records separately.
; with cte as (
select A1, Count(distinct A1) as CountA from tableA)
, ct as (
select distinct FK_A1 , count(b2) as Count from tableB)
select 100 * ct.count/cte.CountA as totalpercentage
from cte
inner join ct
on cte.A1=ct.FK_A1

MySQL trying to reuse results of subquery in an efficient way

I have a query like this:
SELECT q,COUNT(x),y,
(SELECT i FROM (SELECT q,w FROM tableA WHERE conds)
JOIN tableC ON (cond)
WHERE id = t.q)
FROM (SELECT q,w FROM tableA WHERE conds) t
JOIN tableB
GROUP BY q
The subquery (SELECT q,w FROM tableA WHERE conds) returns several hundred rows. After the GROUP BY q there is around 20 rows left.
The subquery (SELECT i FROM (SELECT q,w FROM tableA WHERE conds) join tableC WHERE id = t.q) uses inside of it the exactly same subquery as the one above, but then also selects a fraction of the results based on which q value is currently being grouped.
My problem seems to be this. The performance is too slow because I can't seem to put the WHERE id = t.q inside the (SELECT q,w, FROM Table A WHERE conds) subquery. I can only guess that for every unique value of q, the query is being run, it produces hundreds of rows and then has to perform the WHERE clause on an un-indexed temporary table. I think I need to perform the WHERE before the full join
Any ideas please?
This query could produce the same results, but so much information is missing from the question, who can be sure?
Select
q,
count(x),
y,
i
From
tableA a
inner join
tableC c
on cond and c.id = a.q
cross join -- is this an inner join?
tableB b
Where
conds
Group By
q,
y,
i

How to count number of records as well get the records from the query?

I have 3 tables A,B and C. In the stored procedure,I have used a query to get the result but i also want the total number of records i got from the above query.
Is this possible. I tried using something like this
Select count(*)
from (
select A.Name,B.Address,C.grade
from A,B,C
where A.id=B.id
AND B.Tlno=C.tlno
)
But this is not working.
(1) stop using old-style x,y,z joins.
SELECT A.Name,B.Address,C.grade
FROM dbo.A
INNER JOIN dbo.B ON A.id = B.id
INNER JOIN dbo.C ON B.Tlno = C.tlno;
(2) you can add a count(*) over() to the entire resultset. This is kind of wasteful because it returns the count on every row:
SELECT A.Name, B.Address, C.grade, row_count = COUNT(*) OVER ()
FROM dbo.A
INNER JOIN dbo.B ON A.id = B.id
INNER JOIN dbo.C ON B.Tlno = C.tlno;
You can use a windowing function:
select A.Name,
B.Address,
C.grade,
count(*) over () as total_count
from A,B,C
where A.id=B.id
AND B.Tlno=C.tlno
this will return the total count in each and every row though (but it will be the same number for all rows).
Alternative would be to use the ##rowcount keyword:
SELECT A.Name, B.Address, C.grade, ##rowcount
FROM dbo.A
INNER JOIN dbo.B ON A.id = B.id
INNER JOIN dbo.C ON B.Tlno = C.tlno;
Same result as the windowing function though, so you get the total count on each row. I'm curious if there is a performance difference between the two... (don't have SHOWPLAN permission at my current client unfortunately)
use a table variable as below
declare #num table (accname varchar(200),subnet varchar(200))
insert into #num(accname,subnet) Select a.accountname,s.subnet from tbl_accounts a,tbl_accountsubnet s where a.accountid=s.accountid
select COUNT(*) from #num;

How to express count(distinct) with subquery in MySQL?

A query results a certain number. The query is:
select
count(distinct case when (A or B or C) and D then table_a.field1 else null end)
from table_a
left join table_b on table_b.x = table_a.y
group by table_a.y
;
where A, B, C and D are given conditions. Now, written in this form:
select
sum((select count(1) from table_b where table_b.x = table_a.y and ((A or B or C) and D) ))
from table_a
left join table_b on table_b.x = table_a.y
group by table_a.y
;
the result does not match the one we got with count(distinct).
What is the correct way of writing count(distinct) with a subquery?
It's not at all clear why you need a subquery. You still have the JOIN, so that subquery is potentially going to be "counting" the same rows multiple times.
If you want to get the number of distinct values for field1 in table_a which meets a set of criteria (on table_a), then you don't really need a subquery on table_b to get that. At least, I don't see anyway that you can get that result using a subquery on table_b.
Here's an example that returns an equivalent result:
select (select sum(1) as mycount
from ( select a.field1
from table_a a
left join table_b on table_b.x = a.y
where a.y = t.y
and ( (A or B or C) and D )
and a.field1 IS NOT NULL
group by a.field1
) s
) as mycount
from table_a t
group by t.y
That's really the only way I know to get something equivalent to a COUNT(DISTINCT expr). You've got to do a SELECT expr FROM ... WHERE expr IS NOT NULL GROUP BY expr, and then count the rows it returns. In this case, you could use either a COUNT(1) or a SUM(1).
(I'm not at all sure that answers the question you were asking, but it's my best shot at it.)
(We note that in your original query, you have a GROUP BY table_a.y, so that query can return multiple rows, each with its own count.