Having a query that needs to be optimized, the query looks like below:
SELECT *
FROM TableA
LEFT JOIN TableB ON TableA.column_1 = TableB.column_1
AND TableB.column_2 IS NOT NULL
AND TableB.column_3 IS NULL
AND TableB.column_4 IS NULL
AND TableB.column_5 IS NULL
LEFT JOIN TableC ON TableA.column_1 = TableC.column_1
AND TableC.column_3 IS NULL
AND TableC.column_4 IS NULL
AND TableC.column_5 IS NULL
The slow part in a query is a lot of IS NULL in ON clause. The time execution is around 4+ seconds. After playing with the query for a while i've noticed that IS NULL can be omitted from the fields in ON clause. Like so:
SELECT *
FROM TableA
LEFT JOIN TableB ON TableA.column_1 = TableB.column_1
AND TableB.column_2 IS NOT NULL
AND TableB.column_3
AND TableB.column_4
AND TableB.column_5
LEFT JOIN TableC ON TableA.column_1 = TableC.column_1
AND TableC.column_3
AND TableC.column_4
AND TableC.column_5
The time execution for this query is 53ms!, and the set of records is also the same as we have from the first query. Tried to google it and didn't find anything.
Does anyone know how it works?
MySQL version is 5.7.25
UPDATE
CREATE TABLE TableA (
`column_1` INT(2) NOT NULL,
`column_2` datetime NULL,
`column_3` datetime NULL,
`column_4` datetime NULL,
`column_5` datetime NULL,
)
CREATE TABLE TableB (
`column_1` INT(2) NOT NULL,
`column_2` datetime NULL,
`column_3` datetime NULL,
`column_4` datetime NULL,
`column_5` datetime NULL,
)
CREATE TABLE TableC (
`column_1` INT(2) NOT NULL,
`column_2` datetime NULL,
`column_3` datetime NULL,
`column_4` datetime NULL,
`column_5` datetime NULL,
)
INSERT INTO `TableA` (`column_1`, `column_2`, `column_3`, `column_4`, `column_5`)
VALUES
(1, '2019-08-13 00:00:00', NULL, NULL, NULL);
Didn't include indexes, but each field which is used in ON clause has index
Consider the table:
create table tablename (id int, col datetime);
insert into tablename (id, col) values
(5, null),
(6, '2019-01-06 11:38:41'),
(7, '2019-01-06 11:39:40'),
(8, '2019-01-06 11:39:49');
The query:
select *
from tablename
where col
returns:
| id | col |
| --- | ------------------- |
| 6 | 2019-01-06 11:38:41 |
| 7 | 2019-01-06 11:39:40 |
| 8 | 2019-01-06 11:39:49 |
See the demo.
Meaning that in order to evaluate col as a value of 0 (False) or 1 (True), since the evaluation takes place in the WHERE clause, MySql converts any non null datetime value to a positive number >0, evaluating to True and any null value will evaluate to not True (so treated like False) .
What you describe is the exact opposite.
Because TableB.column_3 IS NULL and just TableB.column_3 when evaluated as >0 or 0 in a WHERE or ON clause return the opposite results.
Related
I am trying to get the order_payment_total of the unique od_grp_id once but while using sum it get added.
CREATE TABLE IF NOT EXISTS `subscription` (
`id` int(11) unsigned NOT NULL,
`od_grp_id` int(11) unsigned NULL,
`user_id` int(11) NOT NULL,
`order_discount` decimal(10, 2) null,
PRIMARY KEY (`id`)
) DEFAULT CHARSET = utf8;
INSERT INTO `subscription` (
`id`, `od_grp_id`, `user_id`, `order_discount`
)
VALUES
(123994, NULL, 115, null),
(124255, NULL, 115, null),
(124703, 1647692222, 115, null),
(125788, 1647692312, 115, '25.00'),
(125789, 1647692312, 115, '5.00');
CREATE TABLE IF NOT EXISTS `online_payment_against_subscription` (
`subscription_od_grp_id` int(11) unsigned NOT NULL,
`order_payment_total` decimal(10, 2) unsigned NOT NULL,
`user_id` int(11) NOT NULL
) DEFAULT CHARSET = utf8;
INSERT INTO `online_payment_against_subscription` (
`subscription_od_grp_id`, `order_payment_total`, `user_id`
)
VALUES
(1643695200, '45.00', 115),
(1647692312, '250.00', 115),
(1647692222, '30.00', 115);
SELECT
sum(y.order_payment_total),
sum(s.order_discount)
FROM
subscription s
LEFT JOIN(
SELECT
SUM(order_payment_total) as order_payment_total,
user_id,
subscription_od_grp_id
FROM
online_payment_against_subscription
GROUP BY
subscription_od_grp_id
) y ON y.subscription_od_grp_id = s.od_grp_id
WHERE
find_in_set(
s.id, '123994,124255,124703,125788,125789'
)
group by
s.user_id
Current Output:
| sum(y.order_payment_total) |sum(s.order_discount) |
|----------------------------|-----------------------|
| 530 | 30 |
Expected Ouput:
| sum(y.order_payment_total) |sum(s.order_discount) |
|----------------------------|-----------------------|
| 280 | 30 |
Sql Fiddle: http://sqlfiddle.com/#!9/5628f5/1
If I understand correctly, The problem is caused by some duplicate od_grp_id from subscription table, so you might remove the duplicate od_grp_id before JOIN, so we might do that in a subquery.
Query 1:
SELECT
SUM(order_payment_total),
SUM(order_discount)
FROM (
SELECT od_grp_id,SUM(order_discount) order_discount
FROM subscription
WHERE find_in_set(id, '123994,124255,124703,125788,125789')
GROUP BY od_grp_id
) s
LEFT JOIN online_payment_against_subscription y ON y.subscription_od_grp_id=s.od_grp_id
Results:
| SUM(order_payment_total) | SUM(order_discount) |
|--------------------------|---------------------|
| 280 | 30 |
I think you are getting this error because every subscription doesn't have an order payment that is you are getting NULL values.
You can try to remove them by using this -
SELECT y.order_payment_total
FROM subscription s
LEFT JOIN(SELECT SUM(order_payment_total) AS order_payment_total, user_id, subscription_od_grp_id
FROM online_payment_against_subscription
GROUP BY subscription_od_grp_id) y ON y.subscription_od_grp_id = s.od_grp_id
WHERE FIND_IN_SET(s.id, '11258,22547,18586')
AND y.order_payment_total IS NOT NULL;
Or you can make NULL values 0 if you required -
SELECT COALESCE(y.order_payment_total, 0) AS order_payment_total
FROM subscription s
LEFT JOIN(SELECT SUM(order_payment_total) AS order_payment_total, user_id, subscription_od_grp_id
FROM online_payment_against_subscription
GROUP BY subscription_od_grp_id) y ON y.subscription_od_grp_id = s.od_grp_id
WHERE FIND_IN_SET(s.id, '11258,22547,18586');
So I have a few tables on mySQL:
CREATE TABLE IF NOT EXISTS `salarygrade` (
`GRADE` INT(11) NOT NULL,
`HOURLYRATE` FLOAT NOT NULL,
PRIMARY KEY (`GRADE`));
===========================================================================
CREATE TABLE IF NOT EXISTS `staffongrade` (
`STAFFNO` INT(11) NOT NULL,
`GRADE` INT(11) NOT NULL,
`STARTDATE` DATE NULL DEFAULT NULL,
`FINISHDATE` DATE NULL DEFAULT NULL,
INDEX `STAFFONGRADE_FK` (`STAFFNO` ASC),
INDEX `STAFFONGRADE2_FK` (`GRADE` ASC),
PRIMARY KEY (`GRADE`, `STAFFNO`),
CONSTRAINT `FK_STAFFONG_STAFFONGR_SALARYGR`
FOREIGN KEY (`GRADE`)
REFERENCES `salarygrade` (`GRADE`),
CONSTRAINT `FK_STAFFONG_STAFFONGR_STAFF`
FOREIGN KEY (`STAFFNO`)
REFERENCES `staff` (`STAFFNO`));
===========================================================================
CREATE TABLE IF NOT EXISTS `campaign` (
`CAMPAIGN_NO` INT(11) NOT NULL,
`TITLE` VARCHAR(30) NOT NULL,
`CUSTOMER_ID` INT(11) NOT NULL,
`THEME` VARCHAR(40) NULL DEFAULT NULL,
`CAMPAIGNSTARTDATE` DATE NULL DEFAULT NULL,
`CAMPAIGNFINISHDATE` DATE NULL DEFAULT NULL,
`ESTIMATEDCOST` INT(11) NULL DEFAULT NULL,
`ACTUALCOST` FLOAT NULL DEFAULT NULL,
PRIMARY KEY (`CAMPAIGN_NO`),
INDEX `OWNS_FK` (`CUSTOMER_ID` ASC),
CONSTRAINT `FK_CAMPAIGN_OWNS_CUSTOMER`
FOREIGN KEY (`CUSTOMER_ID`)
REFERENCES `customer` (`CUSTOMER_ID`)
ON DELETE RESTRICT
ON UPDATE RESTRICT);
===========================================================================
CREATE TABLE IF NOT EXISTS `workson` (
`STAFFNO` INT(11) NOT NULL,
`CAMPAIGN_NO` INT(11) NOT NULL,
`WDATE` DATE NOT NULL,
`HOUR` FLOAT NULL DEFAULT NULL,
PRIMARY KEY (`STAFFNO`, `CAMPAIGN_NO`, `WDATE`),
INDEX `WORKSON_FK` (`STAFFNO` ASC),
INDEX `FK_WORKSON_WORKSON2_CAMPAIGN_idx` (`CAMPAIGN_NO` ASC),
CONSTRAINT `FK_WORKSON_WORKSON2_CAMPAIGN`
FOREIGN KEY (`CAMPAIGN_NO`)
REFERENCES `campaign` (`CAMPAIGN_NO`)
ON DELETE RESTRICT
ON UPDATE RESTRICT,
CONSTRAINT `FK_WORKSON_WORKSON_STAFF`
FOREIGN KEY (`STAFFNO`)
REFERENCES `staff` (`STAFFNO`));
And I want to create a stored procedure called sp_finish_campaign (in c_title varchar(30)) that takes a title of a campaign and finishes the campaign by updating the CAMPAIGNFINISHDATE to the current date and ACTUALCOST to the cost of the campaign, which is calculated from the number of hours different staff put into it on different dates, and the salary grade (this changes based on staffID and the timeframe based on the STARTDATE and FINISHDATE of the staffongrade table.
To calculate the ACTUALCOST, I created a helper function:
DELIMITER //
CREATE FUNCTION rate_on_date(staff_id int, given_date date)
RETURNS int
DETERMINISTIC
BEGIN
DECLARE salaryGrade int;
SET salaryGrade = (select grade from staffongrade
where staffno = staff_id AND (given_date BETWEEN STARTDATE AND FINISHDATE));
RETURN salaryGrade;
END //
DELIMITER ;
Which returns the pay grade based on the staff_id and given_date parameters I give it:
select rate_on_date(1, "2018-02-02") as Grade_On_Date;
For the parameters of this I assume I would have to get it from the workson table which looks like this:
I have tried using a select statement to get the paygrade:
select hourlyrate as 'grade' from salarygrade
where rate_on_date(1, "2018-02-02") = grade;
To calculate ACTUALCOST I assume I would have to do a calculation by multiplying HOUR column with the grade costs, and use the WDATE and STAFFNO columns in the workson table as parameters for my stored procedure that will calculate and update the CAMPAIGNFINISHDATE and ACTUALCOST of the campaign by inputting the campaign title into it.
But how would I go about doing this?
I'm just confused as to how to go about creating this procedure, and also confused about how to properly use these helper functions in my stored procedure.
I feel like this question is quite long but I don't really know what to ask or what direction I should take to solve this problem.
You don't really need a function. mysql can do multi-table updates (see https://dev.mysql.com/doc/refman/8.0/en/update.html) in your case it could look like this
update campaign c
join
(select c.campaign_no,
sum(hour * hourlyrate) cost
from campaign c
join workson w on w.campaign_no = c.campaign_no
join staffongrade s on s .staffno = w.staffno and w.wdate between s.startdate and s.finishdate
join salarygrade g on g.grade = s.grade
group by c.campaign_no
) s
on s.campaign_no = c.campaign_no
set actualcost = s.cost
where c.campaign_no = 1
;
Where the sub query does the needful
if you simplify your data this should be easy to prove;
drop table if exists salarygrade,campaign,workson,staffongrade;
CREATE TABLE `salarygrade`
( GRADE INT NOT NULL,
hOURLYRATE decimal(10,2) NOT NULL
);
insert into salarygrade values(1,10),(2,20);
cREATE TABLE IF NOT EXISTS `staffongrade` (
`STAFFNO` INT(11) NOT NULL,
`GRADE` INT(11) NOT NULL,
`STARTDATE` DATE NULL DEFAULT NULL,
`FINISHDATE` DATE NULL DEFAULT NULL
);
insert into staffongrade values
(1,1,'2019-01-01','2019-06-30'),(1,2,'2019-06-01','2019-12-31'),(2,1,'2019-01-01','2019-01-31');
CREATE TABLE IF NOT EXISTS `campaign` (
`CAMPAIGN_NO` INT(11) NOT NULL,
`CAMPAIGNSTARTDATE` DATE NULL DEFAULT NULL,
`CAMPAIGNFINISHDATE` DATE NULL DEFAULT NULL,
`ESTIMATEDCOST` INT(11) NULL DEFAULT NULL,
`ACTUALCOST` FLOAT NULL DEFAULT NULL
);
insert into campaign values (1,'2019-01-01','2019-12-31',null,null);
CREATE TABLE IF NOT EXISTS `workson` (
`STAFFNO` INT(11) NOT NULL,
`CAMPAIGN_NO` INT(11) NOT NULL,
`WDATE` DATE NOT NULL,
`HOUR` FLOAT NULL DEFAULT NULL
);
insert into workson values
(1,1,'2019-01-01',1),(1,1,'2019-12-01',1),(2,1,'2019-01-01',1);
select * from campaign;
+-------------+-------------------+--------------------+---------------+------------+
| CAMPAIGN_NO | CAMPAIGNSTARTDATE | CAMPAIGNFINISHDATE | ESTIMATEDCOST | ACTUALCOST |
+-------------+-------------------+--------------------+---------------+------------+
| 1 | 2019-01-01 | 2019-12-31 | NULL | 40 |
+-------------+-------------------+--------------------+---------------+------------+
1 row in set (0.00 sec)
Got to dash so I'll leave you to drop the update into a procedure.
IF staffongrade has NULL for finishdate then a bit of data cleansing is required. for simplicity I would create a temporary table to fill in gaps and change the update statement to use the projectfinishdate (if that's not known then substitute a suitable future date). This code would be inserted in your procedure prior to the update
so
insert into staffongrade values
(1,1,'2019-01-01',null),(1,2,'2019-07-01',null),(2,1,'2019-01-01',null);
drop temporary table if exists staffongradetemp;
create temporary table staffongradetemp like staffongrade;
insert into staffongradetemp
select s.STAFFNO,s.GRADE,s.STARTDATE,
case when s.FINISHDATE is not null then s.finishdate
else date_sub((select s1.startdate
from staffongrade s1
where s1.STAFFNO = s.STAFFNO and s1.startdate > s.STARTDATE
order by startdate limit 1), interval 1 day)
end
from staffongrade s
;
select * from staffongradetemp;
+---------+-------+------------+------------+
| STAFFNO | GRADE | STARTDATE | FINISHDATE |
+---------+-------+------------+------------+
| 1 | 1 | 2019-01-01 | 2019-06-30 |
| 1 | 2 | 2019-07-01 | NULL |
| 2 | 1 | 2019-01-01 | NULL |
+---------+-------+------------+------------+
3 rows in set (0.00 sec)
Which leaves all the last finshdates as null which we can trap in the update statement using coalesce
update campaign c
join
(select c.campaign_no,
sum(hour * hourlyrate) cost
from campaign c
join workson w on w.campaign_no = c.campaign_no
join **staffongradetemp s** on s .staffno = w.staffno and w.wdate between s.startdate and **coalesce(s.finishdate,c.CAMPAIGNFINISHDATE)**
join salarygrade g on g.grade = s.grade
where c.campaign_no = 1
group by c.campaign_no
) s
on s.campaign_no = c.campaign_no
set actualcost = s.cost
where 1 = 1;
I have a very simple query but I am a beginner at this and I couldn't understand really what the problem is as it's not working properly in second case:
SELECT a.user_name, a.password, a.id, r.role_name
FROM accounts as a
JOIN roles as r ON a.role=r.id
SELECT accounts.user_name, accounts.password, accounts.id, roles.role_name
FROM accounts
JOIN roles ON accounts.role=roles.id
SELECT *
FROM accounts as a
JOIN roles as r ON a.role=r.id
accounts.role and roles.id linked with foreign key. I try to select everything using * in the third query but it didn't even get anything from second table only got everything from first table(as in the last photo). So what might be the problem ?
This behaviour has no sense, all fields must to appear when you use *
Let's do a test on SQL Fiddle
MySQL 5.6 Schema Setup:
create table t1 ( i int, a char);
insert into t1 values (1,'a');
create table t2 ( i int, b char);
insert into t2 values (1,'a');
Query 1:
select *
from t1 inner join t2 on t1.i = t2.i
Results:
| i | a | i | b |
|---|---|---|---|
| 1 | a | 1 | a |
Query 2:
select *
from t1 x inner join t2 y on x.i = y.i
Results:
| i | a | i | b |
|---|---|---|---|
| 1 | a | 1 | a |
You can see all times all fields appear. May be is a issue with the program you use to connect and make the queries. Check for twice you are executing all the sentence, not only the firsts 2 lines, also check if they are a scroll bar to see more data.
I've restarted the database with given codes:
$mysqli->query('
CREATE TABLE `crm`.`roles`
(
`id` TINYINT(1) NOT NULL AUTO_INCREMENT,
`role_name` VARCHAR(20) NOT NULL,
`edit` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
);') or die($mysqli->error);
$mysqli->query('
CREATE TABLE `crm`.`accounts`
(
`id` INT NOT NULL AUTO_INCREMENT,
`role` TINYINT(1) NOT NULL DEFAULT 1,
`user_name` VARCHAR(20) NOT NULL,
`password` VARCHAR(100) NOT NULL,
`email` VARCHAR(100) NOT NULL,
`first_name` VARCHAR(50) NOT NULL,
`last_name` VARCHAR(50) NOT NULL,
`hash` VARCHAR(32) NOT NULL,
`active` BOOL NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
FOREIGN KEY (`role`) REFERENCES roles(`id`)
);') or die($mysqli->error);
and every combination of SELECT is working fine now. I don't know what the problem was since I don't remember making any changes on the tables.
in the following scenario:
CREATE TABLE `table1` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`text1` varchar(29) NOT NULL,
`flag` bit(1) DEFAULT NULL,
`reference` int(11) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE ,
UNIQUE KEY `idx_text` (`text1`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `table1` (id, text1, flag, reference) VALUES
(31486, 'YWXH-D6N4-XXH6', 0, NULL),
(31487, 'CBH0-UJBC-MFTO', 0, NULL),
(31488, 'FRQM-E6MW-6VFE', 1, 1657),
(31489, 'LZOS-EYDT-1BBF', 0, NULL),
(31490, 'D1XQ-YKAX-XQRC', 0, NULL);
CREATE TABLE `table2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`value1` int(11) NOT NULL,
`value2` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `value1` (`value1`),
KEY `value2` (`value2`)
) ENGINE=MyISAM AUTO_INCREMENT=20068 DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED;
INSERT INTO table2 (id, value1, value2) VALUES
(1657, 1891, 1748);
-- the tables are shortened from "real" tables, i used SHOW CREATE <table> to create this script.
are the results of the following queries different.
here mysql returns for the record with id 31488 and 31490 the wrong value for the bit-field:
Query 1:
SELECT m.id, m.text1, m.flag, m.reference
FROM table1 AS m LEFT JOIN table2 AS v ON v.id = m.reference
GROUP BY m.text1 ORDER BY m.text1 DESC LIMIT 0, 5;
returns the correct result:
id | text1 | flag | reference
31487 | CBH0-UJBC-MFTO | 0 | NULL
31490 | D1XQ-YKAX-XQRC | 0 | NULL
31488 | FRQM-E6MW-6VFE | 1 | 1657
31489 | LZOS-EYDT-1BBF | 0 | NULL
31486 | YWXH-D6N4-XXH6 | 0 | NULL
while Query 2
SELECT m.id, m.text1, m.flag, m.reference
FROM table1 AS m LEFT JOIN table2 AS v ON v.id = m.reference
GROUP BY m.text1 ORDER BY m.text1 DESC LIMIT 0, 4;
returns this:
id | text1 | flag | reference
31487 | CBH0-UJBC-MFTO | 0 | NULL
31490 | D1XQ-YKAX-XQRC | 1 | NULL
31488 | FRQM-E6MW-6VFE | 0 | 1657
31489 | LZOS-EYDT-1BBF | 0 | NULL
so here is my question:
Im using Joomla CMS, and in the code of the component i can change the whole query except the LIMIT-part.
Joomla add the limit part to the query because of the pagination.
Is there a way to change the query that it works with the LIMIT-command?
oh, my MySQL-Version on Server is 5.1.61 (but this bug still exists on my client v5.5.16)
Your a) not inserting the data correctly - see the BIT data type docs and b) not selecting the data correctly - see the docs on the Bit-Field Literals
You need to insert using the following syntax
INSERT INTO `table1` (id, text1, flag, reference) VALUES
(31486, 'YWXH-D6N4-XXH6', b'0', NULL),
(31487, 'CBH0-UJBC-MFTO', b'0', NULL),
(31488, 'FRQM-E6MW-6VFE', b'1', 1657),
(31489, 'LZOS-EYDT-1BBF', b'0', NULL),
(31490, 'D1XQ-YKAX-XQRC', b'0', NULL);
Then select like this :
SELECT m.id, m.text1, bin(m.flag), m.reference
FROM table1 AS m LEFT JOIN table2 AS v ON v.id = m.reference
GROUP BY m.text1 ORDER BY m.text1 DESC LIMIT 0, 4;
Then it all works as expected
I have a MySQL query to select all product id's with certain filters applied to the products. This query
works but I want to learn to improve this query. Alternatives for this query are welcome with explanation.
SELECT kkx_products.id from kkx_products WHERE display = 'yes' AND id in
(SELECT product_id FROM `kkx_filters_products` WHERE `filter_id` in
(SELECT id FROM `kkx_filters` WHERE kkx_filters.urlname = "comics" OR kkx_filters.urlname = "comicsgraphicnovels")
group by product_id having count(*) = 2)
ORDER BY kkx_products.id desc LIMIT 0, 24
I've included the structure of the tables being used in the query.
EXPLAINkkx_filters;
Field Type Null Key Default Extra
id int(11) unsigned NO PRI NULL auto_increment
name varchar(50) NO
filtergroup_id int(11) YES MUL NULL
urlname varchar(50) NO MUL NULL
date_modified timestamp NO CURRENT_TIMESTAMP
orderid float(11,2) NO NULL
EXPLAIN kkx_filters_products;
Field Type Null Key Default Extra
filter_id int(11) NO PRI 0
product_id int(11) NO PRI 0
EXPLAIN kkx_products;
Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
title varchar(255) NO
urlname varchar(50) NO MUL
description longtext NO NULL
price float(11,2) NO NULL
orderid float(11,2) NO NULL
imageurl varchar(255) NO
date_created datetime NO NULL
date_modified timestamp NO CURRENT_TIMESTAMP
created_by varchar(11) NO NULL
modified_by varchar(11) NO NULL
productnumber varchar(32) NO
instock enum('yes','no') NO yes
display enum('yes','no') NO yes
Instead of using inline queries in your criteria statements, try using the EXISTS block...
http://dev.mysql.com/doc/refman/5.0/en/exists-and-not-exists-subqueries.html
You will be able to see the difference in your explain plan. Before you had a query executing for each and every record in your result set, and every result in that inline view result set had its own query executing to.
You see how nested inline views can create an exponential increase in cost. EXISTS doesn't work that way.
Example of the use of EXISTS:
Consider tbl1 has columns id and data. tbl2 has columns id, parentid, and data.
SELECT a.*
FROM tbl1 a
WHERE 1 = 1
AND EXISTS (
SELECT NULL
FROM tbl2 b
WHERE b.parentid = a.id
AND b.data = 'SOME CONDITIONAL DATA TO CONSTRAIN ON'
)
1) We can assume the 1 = 1 is some condition that equates to true for every record
2) Doesn't matter what we select in the EXISTS statment really, NULL is fine.
3) It is important to look at b.parentid = a.id, this links our exist statement to the result set