mapping Inheritance and native query in doctrine - mysql

I have next structure :
+------+
| |
| A1 | Class A1
| |
+--+---+ Class A2 - child
^ Class A3 - child
|
| A2->B1 (Class B1)
+--------+--------+ A3->B2 (Class B2)
| |
| |
+-----+ +--+---+ +--+--+ +-----+
| | | | | | | |
| B1 +---+ A2 | | A3 +---+ B2 |
| | | | | | | |
+-----+ +------+ +-----+ +-----+
It's single table inheritance so A1,A2,A3 are in single DB table (a1). I need to creative Native Query and mapping that will load all entities from single table with all associated entities (B1, B2) at once. Query looks like this :
SELECT a1.*, b1.id AS b1_id,...,b2.id AS b2_ID...
FROM a1
LEFT JOIN b1 ON (a1.b1 = b1.id)
LEFT JOIN b2 ON (a1.b2 = b2.id)
I have try something like this :
$mapping = new ResultSetMapping();
$mapping->addEntityResult(A1::class, 'a');
$mapping->addFieldResult('a', 'id', 'id');
...
$mapping->addMetaResult('a', 'a_type', 'a_type');
$mapping->setDiscriminatorColumn('a', 'a_type');
but how to map associated entities (B1,B2) ? I have try addJoinedEntityResult but it's require to use child class instead of base class. Is it possible to make such mapping? I didn't find any example of such case on DOCTRINE NATIVE QUERY

Related

MySQL JSON wildcards

I'm trying to obtain all IDs from table A of the elements which are in a JSON array in table B. My problem is that I don't know how to use wildcard symbols with JSON.
Table A looks like this
+-----------------------+--------------------+
| Identifier (TINYTEXT) | Filter (JSON) |
+-----------------------+--------------------+
| Obj1 | ['Test1', 'Test2'] |
| Obj2 | ['Test3', 'Test4'] |
+-----------------------+--------------------+
and table B looks like this
+-----------+--------------------+
| UID (INT) | Object (TINYTEXT) |
+-----------+--------------------+
| 1 | xyzTest1, abc |
| 2 | xyzTest2, abc |
| 3 | xyzTest3, abc |
| 4 | xyzTest4, abc |
+----------------+---------------+
I want to use A.Identifier as the input to get B.UID as the output, applying the filter A.Filter on B.Object using wildcard symbols.
Example:
I have A.Identifier = 'Obj1' and want to find all B.UID for the corresponding B.Object that contain Test1 or Test2 (A.Filter). In this case, the output would be 1 and 2.
The SQL code without the inner join I would manually use for this is
SELECT UID FROM B WHERE Object LIKE '%Test1%' OR Object LIKE '%Test2%';

MS Access Update on specific SQL select same table

I'm currently trying to update an existing database (removing duplicates).
You can see the structure as follows :
I have a database on which specific entries are marked as "Main". These entries need to be updated with data from duplicate records, only having the same name.
(Updated table to reflect my question better)
It would look like this:
+----+------+-----------------+--------------+---------+
| ID | Name | Field-To-Update | Duplication | Source |
+----+------+-----------------+--------------+---------+
| . | A | xxx | Main | 1 |
| . | A | yyy | "" | 2 |
| . | A | zzz | "" | 3 |
| . | B | foo | "" | 1 |
| . | B | bar | Main | 2 |
+----+------+-----------------+--------------+---------+
Should result in
+----+------+-----------------+--------------+-----------------------------------------------+
| ID | Name | Field-To-Update | Duplication | Source |
+----+------+-----------------+--------------+-----------------------------------------------+
| . | A | yyy | Main | 1 |
| . | A | yyy | "" | 2 |
| . | A | zzz | "" | 3 (should be updated from a specific source) |
| . | B | bar | "" | 1 |
| . | B | bar | Main | 2 (should be updated from a specific source) |
+----+------+-----------------+--------------+-----------------------------------------------+
Do any of you have an idea how to tackle this? I've tried with multiple queries for a couple of days now without any success.
you could use a update with join
update t
set t.field_to_update = x.field_to_update
from your_table t
inner join ( select name, field_to_update
from your_table
where Duplication <> 'Main') x
) on t.name = x.name
where t.Duplication = 'Main'
Bizarre requirement. You say you are updating to remove duplicates, however, it looks to me like you are creating duplicates.
There are only 2 records for each Name? Try:
UPDATE Table INNER JOIN
(SELECT Name, [Field-To-Update]
FROM Table
WHERE Duplication Is Null) AS Query1 ON
Table.Name = Query1.Name SET Table.[Field-To-Update] = [Query1]![Field-To-Update] WHERE Duplication = "Main";
Name is a reserved word in Access. Should not use reserved words as name for anything.
Darn! Did not see #scaisEdge answer before posting.
I tried the <> "Main" criteria and it did not work which was surprising - no records returned. So I switched to the Is Null parameter.
If you want to pull value from the maximum Source for each Name, then need a query that does that. Review http://allenbrowne.com/subquery-01.html#TopN. Then use that query in the above example as Query1.

INNER JOIN same value, but the difference is the other table are having extra word in front of the value

As I said in the title, or maybe my question is a little bit confusing. Here it is....
So, I want to combine 2 tables using INNER JOIN (ofcourse) with some difference.
This is my tables
Table 1, PK = steam_id
SELECT * FROM nmrihstats ORDER BY points DESC LIMIT 4;
+---------------------+----------------+--------+-------+--------+
| steam_id | name | points | kills | deaths |
+---------------------+----------------+--------+-------+--------+
| STEAM_0:1:88467338 | Alan14 | 50974 | 5438 | 12 |
| STEAM_0:0:95189481 | ? BlacKEaTeR ? | 35085 | 24047 | 316 |
| STEAM_0:1:79891668 | Lowell | 34410 | 44076 | 993 |
| STEAM_0:1:170948255 | Rain | 29780 | 30167 | 278 |
+---------------------+----------------+--------+-------+--------+
4 rows in set (0.01 sec)
Table 2, PK = authid
SELECT * FROM store_players ORDER BY credits DESC LIMIT 4;
+-----+-------------+---------------+---------+--------------+-------------------+
| id | authid | name | credits | date_of_join | date_of_last_join |
+-----+-------------+---------------+---------+--------------+-------------------+
| 309 | 1:88467338 | Alan14 | 15543 | 1475580801 | 1482260232 |
| 368 | 1:79891668 | Lowell | 10855 | 1475603908 | 1482253619 |
| 256 | 1:128211488 | Fuck[U]seLF | 10422 | 1475570061 | 1482316480 |
| 428 | 1:74910707 | Mightybastard | 7137 | 1475672897 | 1482209608 |
+-----+-------------+---------------+---------+--------------+-------------------+
4 rows in set (0.00 sec)
Now, how can I use INNER JOIN without doing like removing "STEAM_0:" or adding it. Also with explanation, please
You can join witn like operator, e.g.:
SELECT n.*, sp.*
FROM nmrihstats n JOIN store_players sp ON n.steam_id LIKE CONCAT('%', sp.authid);
Here's the SQL Fiddle.
Another approach would be to use String functions of MySQL to extract out relevant part from steam_id but I believe that's not what you want:
SELECT SUBSTR(steam_id, LOCATE('STEAM_0:', steam_id) + CHAR_LENGTH('STEAM_0:'))
FROM nmrihstats;
it is not possible, you need to remove "STEAM_0:", matching with WHERE, using substring for remove STEAM_0: from column equals to column in other table, or a new field into the T1 without "STEAM_0:", that 2 columns match for INNER JOIN

Mysql query to extract tld from dns domain names

In this practice, I'd like to extarct the domain name from the TLD (Top Level Domain) given the following tables.
Table name: dns
+---------------------------+
| dnsdomain |
+---------------------------+
| ns2.hosting.indo.net.id. |
| ns1.onepanel.indo.net.id. |
| ns-1591.awsdns-06.co.uk. |
| mail189.atl21.rsgsv.net. |
| gli.websitewelcome.com. |
| ns2.metrolink.pl. |
| ns1.metrolink.pl. |
| ns-1591.awsdns-06.co.uk. |
| NS3.METRORED.HN. |
| NS.METRORED.HN. |
| ns2.hosting.indo.net.id. |
| ns1.onepanel.indo.net.id. |
| www.csis.ul.ie. |
+---------------------------+
and
Table name: tld
+----------+
| tld |
+----------+
| .net.id. |
| .co.uk. |
| .net. |
| .com. |
| .pl. |
| .uk. |
| .hn. |
| .id. |
| .ie. |
+----------+
I'd like to print out the dnstomain with its related tld. I perform the following mysql query:
select test.dnsdomain , tld.tld from test join tld where locate(tld.tld, test.dnsdomain, length(test.dnsdomain) - length (tld.tld) )!= 0;
and get the below table:
+---------------------------+----------+
| dnsdomain | tld |
+---------------------------+----------+
| ns2.hosting.indo.net.id. | .net.id. |
| ns1.onepanel.indo.net.id. | .net.id. |
| ns-1591.awsdns-06.co.uk. | .co.uk. |
| mail189.atl21.rsgsv.net. | .net. |
| gli.websitewelcome.com. | .com. |
| ns2.metrolink.pl. | .pl. |
| ns1.metrolink.pl. | .pl. |
| ns-1591.awsdns-06.co.uk. | .uk. |
| NS3.METRORED.HN. | .hn. |
| NS.METRORED.HN. | .hn. |
| ns2.hosting.indo.net.id. | .id. |
| ns1.onepanel.indo.net.id. | .id. |
| www.csis.ul.ie. | .ie. |
+---------------------------+----------+
The problem with my query is that for every single record in table 'test' it does not check all the tld from table 'tld' that's why I see something like:
| ns-1591.awsdns-06.co.uk. | .uk. |
where as the expected result would be like:
| ns-1591.awsdns-06.co.uk. | .co.uk. |
What I am doing wrong?
Try Group By function. This statement works in mysql :
select test.dnsdomain , tld.tld ,
max(length(tld.tld)) as x
from test
join tld
where locate(tld.tld, test.dnsdomain, length(test.dnsdomain) - length (tld.tld) )!= 0;
group by test.tnsdomain
OR
select test.dnsdomain , max(tld.tld) as tld
from test
join tld
where locate(tld.tld, test.dnsdomain, length(test.dnsdomain) - length (tld.tld) )!= 0;
group by test.tnsdomain
You're not doing anything wrong. That dnsname 'blah.co.uk.' matches both '.co.uk.' and '.uk.'. Both rows are being returned.
Sounds like you want to filter out all but the "longest" matching tld.
NOTE: I'd prefer to use the RIGHT() function to extract the rightmost portion from dnsdomain. (That's just easier for me to understand, but it should be equivalent to the expression you are using.)
Reference: RIGHT() https://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_right
One option to filter out the shorter matches is to use a correlated subquery to determine the maximum length of all of the tld that match, and only return the tld that has that length.
For example:
SELECT test.dnsdomain
, tld.tld
FROM test
JOIN tld
ON tld.tld = RIGHT(test.tndsdomain,CHAR_LENGTH(tld.tld))
WHERE CHAR_LENGTH(tld.tld) =
( SELECT MAX(CHAR_LENGTH(m.tld))
FROM tld m
WHERE m.tld = RIGHT(test.tndsdomain,CHAR_LENGTH(m.tld))
)
You could get an equivalent result using a JOIN operation to an inline view, it does basically the same thing:
SELECT test.dnsdomain
, tld.tld
FROM test
JOIN tld
ON tld.tld = RIGHT(test.tndsdomain,CHAR_LENGTH(tld.tld))
JOIN ( SELECT n.dnsdomain
, MAX(CHAR_LENGTH(m.tld)) AS tld_len
FROM test n
JOIN tld m
ON m.tld = RIGHT(n.tndsdomain,CHAR_LENGTH(m.tld))
GROUP BY n.dnsdomain
) o
ON o.dnsdomain = test.dnsdomain
AND o.tld_len = CHAR_LENGTH(tld.tld)
Also, it's better practice to use CHAR_LENGTH() function than LENGTH() function. The LENGTH() function returns a number of bytes, which is the same as the number of characters, for single byte character sets (like latin1), but with multibyte charactersets, the number of characters can be less than the number of bytes.)

Transforming one record into multiple records of a resultset

I'm creating a MySQL view for a server application that connects directly to the database server. I didn't like the way the application's schema is so I went with my own structure. Originally, I was going to use the data to create static configuration files, but that is no longer an option.
Anyway, I'll be using several rows from different tables to create this view. There is a 1:many relationship between table A and the view and a 1:1 relationship for table B. It's the 1:many that's throwing me off.
In table A, I have the following:
+--------------------------------+
| id | name | timeout | any |
+--------------------------------+
| 1 | Main | 10 | 1 |
+--------------------------------+
In table B, I have the following:
+-------------------+
| id | a_id | route |
+-------------------+
| 1 | 1 | 123 |
+-------------------+
| 2 | 1 | 321 |
+-------------------+
For the view, the two tables will be joined like so:
+-------------------------------------+
| name | app | data |
+-------------------------------------+
| Main | timeout | 10 |
+-------------------------------------+
| Main | dialany | 1 |
+-------------------------------------+
| Main | routeto | 321 |
+-------------------------------------+
| Main | routeto | 123 |
+-------------------------------------+
I'm not even sure if there's a name for this (or if it's even possible) but any help to get started would be fantastic.
You'd use a UNION to get the individual rows from the first table, something like this:
SELECT name, 'timeout' as app, timeout FROM A WHERE id = 1
UNION SELECT name, 'dialany' as app, `any` FROM A WHERE id = 1
And then UNION in the other table:
UNION SELECT A.name, 'routeto' as app, B.data FROM A
JOIN B ON A.id = B.a_id
WHERE A.id = 1
And you should have what you want.