Join columns with specific match case - mysql

I have two tables TableA and TableB.
The TableA having column called Code Like
'A'
'AB'
'B'
'BB'
In TableB I have column called pnrcode like
'A001'
'AB001'
'B001'
'BC001'
Both tables have no relationship.
I want to join this two table based on TableA code with TableB pnrcode with matching the characters based on TableA

If you are using MySql 8.* you can use REGEXP_SUBSTR in a subquery to join the two tables
SELECT a.*, b.prncode
FROM TableA a
JOIN (SELECT *, REGEXP_SUBSTR(prncode, '^[A-Z]+') as code
FROM TableB) b ON a.code = b.code

Try this below code with a join. You can use any join based on your requirement.
SELECT *
FROM TableA
INNER JOIN TableB
ON TableA.Code =
left( TableB.pnrcode, length(TableB.pnrcode) - length( reverse( concat(TableB.pnrcode, "1") ) + 0 ) + 1 );

You can use replace() to remove code from pnrcode.
If what is left is a number > 0 (MySql does implicit conversion) then join on that:
select *
from tablea a left join tableb b
on replace(b.pnrcode, a.code, '') > 0
I assume that all pnrcodes have numeric part other than 0.
See the demo.
Results:
| code | pnrcode |
| ---- | ------- |
| A | A001 |
| AB | AB001 |
| B | B001 |
| BB | |

with res as
(SELECT dbo.AlphaOnly(a.Prccode) as Prccode1,* from TableA a)
SELECT * from res join Tableb b on b.Code=res.prccode1
go

Related

JOIN two query results (having WHERE and IN clauses + sub queries)

Trying to recreate the problem below (not including IN clause and sub-queries):
/* this is query 1 */
Select A.column_1,B.keyValue from table1 as A, table2 as B where
A.someColumn = B.someColumn and B.someotherColumn = 10
/* query 1 gives */
column1 | keyValue
_________________
data-A1 | key-1
data-A2 | key-2
data-A3 | key-3
/* this is query 2 */
Select AVG(ratings) as ratings, C.keyValue from table3 as C,
table4 as D where C.someColumn = D.someColumn and D.someotherColumn = 'abc'
/* query 2 gives */
ratings | keyValue
_________________
rating-1 | key-1
rating-2 | key-2
rating-3 | key-3
/* this is the desired result */
column1 | ratings | keyValue
_________________
data-A1 | rating-1 | key-1
data-A2 | rating-2 | key-2
data-A3 | rating-3 | key-3
I googled it up, found mysql join is the solution
SELECT table1.id, table2.column1, table1.column2 FROM table1
INNER JOIN table2 ON table1.id = table2.id;
But this a very basic example involving only two tables, my first query actually involves 5 tables and second query involves 4 tables with multiple WHERE and IN clauses + sub queries. I am unable to implement this JOIN logic with my complex queries having. This is what I tried but its giving me an error after "JOIN" keyword :
Select * from (Select A.column_1,B.keyValue from table1 as A, table2 as B
where A.someColumn = B.someColumn and B.someotherColumn = 10) as first
JOIN
Select * from (Select AVG(ratings) as ratings, C.keyValue from table3 as C,
table4 as D where C.someColumn = D.someColumn and D.someotherColumn = 'abc')
as second ON first.keyValue = second.keyValue;
Any help would be appreciated.
I don't know the structure of your 4 tables but based on your 2 queries, you can do the following:
select
X.column_1,
Y.ratings,
X.key_value
From
(
Select
A.column_1,
B.keyValue
from
table1 as A,
table2 as B
where
A.someColumn = B.someColumn
and B.someotherColumn = 10
)
X
INNER JOIN
(
Select
AVG(ratings) as ratings,
C.keyValue
from
table3 as C,
table4 as D
where
C.someColumn = D.someColumn
and D.someotherColumn = 'abc'
)
Y
on X.keyvalue = Y.keyvalue;
X and Y are called derived tables.
P.S: It might be possible to create a better query if we know the structure of your underlying tables, sample data and what you are trying to achieve. This is the best answer I can give you based on the information.

MySQL create field on main table with concatenated rows

Input two table, TABLE A and TABLE B
TABLE A TABLE B
A_ID | A A_ID | B
1 | a 1 | b
2 | a1 1 | b1
3 | a2 2 | b2
Expecting Output TABLE C
TABLE C
A_ID | A | C
1 | a | b,b1 <--- Concat all rows in TABLE B with ','
2 | a1 | b2
3 | a2 | NULL <--- NULL if no matched A_ID in TABLE B
Column C finds all matched A_ID and concat All rows of B in to new TEXT field.
Can this be done only with MySQL query?
insert into TABLE_C
SELECT
A1.A_ID,
A1.A,
GROUP_CONCAT(B1.B) as 'C'
FROM `TABLE_A` A1
LEFT JOIN `TABLE_B` B1
ON A1.A_ID=B1.A_ID
GROUP BY A1.A_ID;
left join on above sql helps to get the common matching (relating) rows from two tables 'TABLE_A' and 'TABLE_B' and group by id helps to get the rows which are not not matched (not relate to each other which returns the result set for 2,a1 and 3,null). group_concat bind two columns and by default it is comma separated . If we want some other separator then only we need to used group_concat with separator statement. And also insert select helps to insert a results row into a new table 'TABLE_C' which is ofcourse need to created on prior
Try this using GROUP_CONCAT() function.
SELECT
tbla.A_ID,
tbla.A,
GROUP_CONCAT(tblb.B)
FROM `TABLE A` tbla
LEFT JOIN `TABLE B` tblb
ON tbla.A_ID=tblb.A_ID
GROUP BY tbla.A_ID;
Use group_contact to aggregate values of column B in TABLE B within a group. Insertion of values to TABLE C can be done using INSERT .. SELECT
insert into tablec
select a.a_id, a.a, group_concat(b separator ',')
from tablea a
left join tableb b on (a.a_id = b.a_id)
group by a.a_id, a.a;

Select all rows that have same ID

I have this table:
ID | Part
1 | A
1 | B
1 | C
2 | B
2 | C
3 | A
3 | D
3 | E
4 | B
4 | D
and want a query that will grab all ID's that have an A, and return a list of all other parts with that ID.
e.g: Want Parts related to B:
Part | Count
A | 1
C | 2
D | 1
What I have currently:
SELECT * FROM tble WHERE ID IN (SELECT DISTINCT ID FROM tble t WHERE Part = ?)
GROUP BY Part ORDER BY COUNT(Part) DESC
This works, but is quite slow and I'm looking to improve it, but having difficulty
Your query is not unreasonable, although the distinct is unnecessary and I would use exists rather than in. And, the outer select needs to be fixed for the aggregation
SELECT t.part, COUNT(*)
FROM tble t
WHERE EXISTS (SELECT 1 FROM tble t2 WHERE t2.ID = t.ID AND t2.Part = ?)
GROUP BY t.Part
ORDER BY COUNT(*) DESC;
Then, to optimize this query, you want an index:
create index idx_tble_id_part on tble(id, part);
Simplify this.. Once you have the logic down, then add back in the SELECT * FROM..
SELECT Part, COUNT(Part) As Count_of_Part
GROUP BY Part ORDER BY COUNT(Part) DESC
Do a join from the table back to itself on ID, and then count the distinct values that pop up:
SELECT b.part, COUNT(DISTINCT b.id)
FROM
table as a
INNER JOIN table as b ON
a.id = b.id AND
a.part <> b.part
WHERE
a.part = 'B'
GROUP BY b.part
This can be simply done by joining back to the table:
SELECT t1.part
,count(*)
FROM tble t1
INNER JOIN tble t ON t.id = t1.id
AND t.part = 'B'
AND t1.part <> t.part
GROUP BY t1.part
SQL Fiddle Demo
You should be able to do this by grouping the data.
Try something like this:
SELECT part, COUNT(id) AS TotalCountId
FROM TABLE_NAME
GROUP BY ID

SQL query for joining one or another table

I have two tables TableA and TableB with some data:
IDA|TDATA IDB|TDATA
---+----- ---+-----
1 | A1 1 | B1
2 | A2 2 | B2
and one central table:
ID|TID|TAB|CDATA
--+---+---+-----
10| 1 | A | C1
11| 2 | B | C2
12| 2 | A | C3
Data from central table should be joined with data from TableA or TableB (joining columns TID and TAB). TID is reference to ID in joined table IDA or IDB and column TAB defines which table should be joined. So the final result from query should look like:
ID|TDATA|CDATA
--+-----+-----
10| A1 | C1
11| B2 | C2
13| A2 | C3
How this SQL query should look like?
You can do something like
SELECT c.id,
coalesce( a.tdata, b.tdata ) tdata,
c.cdata
FROM central_table c
LEFT OUTER JOIN tableA a
ON( c.tid = a.ida AND
c.tab = 'A' )
LEFT OUTER JOIN tableB b
ON( c.tid = b.idb AND
c.tab = 'B' )
I would seriously question the data model here, however. If you don't know whether a column in C references a column in A or B, something is generally incorrect in the data model. Fixing the data model will make this (and all your other queries, most likely) much easier to write and much easier to optimize.
If all you want is TAB followed by TID, then the following will work:
SELECT ID, CONCAT(TAB, CAST(TID AS CHAR[2])) AS TDATA, CDATA FROM CentralTable;
If the table names are constant (e.g., nothing other than A or B will be in there), then you can do:
(SELECT ID, TDATA, CDATA FROM CentralTable a
JOIN TableA b ON (a.ID = b.IDA) WHERE a.TAB = 'A')
UNION ALL
(SELECT ID, TDATA, CDATA FROM CentralTable a
JOIN TableB b ON (a.ID = b.IDB) WHERE a.TAB = 'B')

mySQL Subquery - Single pass if possible

I am looking to perform a query that will return data from a number of tables in mySQL that will require some subqueries however I am not sure if what I am trying to achieve is even possible in a single pass.
I have the below as an example (i know this doesn't work but gives you the idea)
SELECT field_id, field_1,
(SELECT subfield_1 FROM tableb WHERE subfield_id = field_3) AS field_a,
(SELECT subfield_1 FROM tableb WHERE subfield_id = field_4) as field_b
FROM tablea WHERE field_2 = 123
This will pull 2 entries from a second table based on 2 different columns in the primary table.
tablea
----------
field_id, bigint
field_1, varchar(50)
field_2, int
field_3, bigint
field_4, bigint
tableb
----------
subfield_id, bigint
subfield_1, varchar(50)
Use JOINs. Depending on whether field_3 and field_4 are NULLable or not use either LEFT JOIN (as in example below) or INNER JOIN
SELECT field_id, field_1, b1.subfield_1 field_a, b2.subfield_1 field_b
FROM tablea a LEFT JOIN tableb b1
ON a.field_3 = b1.subfield_id LEFT JOIN tableb b2
ON a.field_4 = b2.subfield_id
WHERE a.field_2 = 123
Sample output:
| FIELD_ID | FIELD_1 | FIELD_A | FIELD_B |
|----------|---------|-----------|-----------|
| 1 | 11 | subvalue1 | subvalue5 |
| 2 | 22 | subvalue4 | subvalue2 |
| 3 | 33 | subvalue2 | (null) |
Note: Make sure that you have indices on field_3 and field_4
Here is SQLFiddle demo
What you are trying to achieve is possible only if your sub query returns one row .
for example here
(SELECT subfield_1 FROM tableb WHERE subfield_id = field_3)
field 3 should be a primary key for tableb
You could perform an outer join, where you will see the same result without having the delay of having to use a correlated subquery.
The outer join has the advantage that all rows from tablea will be displayed, regardless of whether there is an accompanying value within the tableb subqueries.
A normal join would instead only return rows where all three tables contained field_3 and field_4, and as a result the row for field_id = 3 would not be returned.
Example:
SELECT field_id,
field_1,
s1.subfield_1 as field_a,
s2.subfield_1 as field_b
FROM tablea AS a
LEFT JOIN tableb AS s1 ON a.field_3 = s1.subfield_id
LEFT JOIN tableb AS s2 ON a.field_4 = s2.subfield_id
WHERE field_2 = 123;