Subqueries in SQL for select - mysql

I want to filter records in my cursor using inner and outer select statements.
How do I achieve that?
I want only '_02' records from both tables.
table A:
col1
1122_01
1234_02
3456_02
7899_02
table B:
col1
1111_02
1234_02
4567_02
table Final:
col1
3456_02
7899_02
SELECT distinct a.col1
FROM A a
WHERE NOT EXISTS (SELECT 1 FROM B b
WHERE b.col1 = a.col1
and b.col1='02')
and a.col1='02'
will this work?
Or this?
SELECT distinct t.item, t.skuloc loc
FROM SCPOMGR.UDT_DFUTOSKUMAP t
, SCPOMGR.udt_gen_param G
WHERE NOT EXISTS (SELECT *
FROM SCPOMGR.SKU s1
, SCPOMGR.udt_gen_param G
,SCPOMGR.UDT_DFUTOSKUMAP t
WHERE s1.ITEM = t.ITEM
AND s1.LOC = t.SKULOC
and G.region='XYZ'
and G.jda_code= substr(s1.loc,-2,2)
)
and G.region='XYZ'
and G.jda_code= substr(T.SKUloc,-2,2)

It looks like you want the set of
distinct values of A.col1
for which the same value does not exist in B.col1
ending in _02.
If you will work using SQL it is vitally important to learn to specify what you want very precisely. SQL is, at is heart, a scheme for specifying sets of data. Use the concepts of elementary set theory when specifying requirements to be realized with SQL.
Once you have a precise specification, writing it in SQL is usually easy. If you can't express what you want in SQL, revisit the specification.
In your case:
SELECT DISTINCT A.col1
FROM A
LEFT JOIN B ON A.col1 = B.col1
WHERE B.col1 IS NULL
AND A.col1 LIKE `%_02`
This uses LIKE '%suffix for the third requirement, the old LEFT JOIN ... IS NULL trick for the second requirement, and DISTINCT A.col1 for the first.
This particular query works in various SQL dialects. Cursors have nothing to do with this case.

Related

sql join issues with different data

I want to join two tables with different data and data type is same.
In tableA the column col1 is with varchar datatype i.e. 123 and in tableB the column col1 is with varchar datatype i.e. ABC-123
Is there any way to join both columns by adding ABC as prefix to col1 in table 1 or by removing prefix ABC from col1 table 2.
You can use CONCAT(), as in:
select *
from table_a a
join table_b b on concat('ABC-', a.col1) = b.col2
This issue is quite common, specially in old databases, where you need to join VARCHAR columns with NUMERIC ones, since the designers back in the 90s though it that way.
Just use function CONCAT() at the ON clause of INNER JOIN
select * from
tableA a inner join tableB b
on CONCAT('ABC-', a.col1) = b.col2

Which of the following query is optimised/preferred

Consider two table
tableA and tableB
tableA
|id|driver_id|vehicle_id|is_allowed|license_number|driver_name|
tableB
|id|driver_id|vehicle_id|offence|payable_amount|driver_name|
Goal: find driver_id and vehicle_id of allowed driver whose name is XYZ.
Query1:SELECT * FROM tableA,tableB {join-condition}{filter-condition}
SELECT tableA.driver_id,tableA.vehicle_id FROM tableA,tableB
WHERE
tableA.driver_id=tableB.driver_id AND
tableA.vehicle_id=tableB.vehicle_id AND
tableA.driver_name='XYZ' AND
tableB.driver_name='XYZ' AND
tableA.is_allowed = 1
Query2:SELECT * FROM (SELECT * FROM tableA {filter-condition}) JOIN (SELECT * FROM tableB {filter-condition}) ON {join-condition}{filter-condition}
SELECT tableAA.driver_id,tableAA.vehicle_id FROM
(SELECT tableA.driver_id,tableA.vehicle_id from tableA WHERE tableA.driver_name='XYZ' AND
tableA.is_allowed = 1) as tableAA,
JOIN
(SELECT tableB.driver_id,tableB.vehicle_id from tableB WHERE tableB.driver_name='XYZ') as tableBB
ON
tableAA.driver_id=tableBB.driver_id AND
tableAA.vehicle_id=tableBB.vehicle_id
which type of query is readable, optimized and according to standard.
A correct version would look like this:
SELECT a.driver_id, a.vehicle_id
FROM tableA a JOIN
tableB b
ON a.driver_id = b.driver_id AND
a.vehicle_id = b.vehicle_id
WHERE a.driver_name = 'XYZ' AND
b.driver_name = 'XYZ' AND
a.is_allowed = 1;
Notes:
JOIN is accepted as the right way to combine tables in the FROM clause. Simple rule: Never use commas in the FROM clause.
The ON clause should contain all predicates that contain columns from more than one table.
The use of table aliases is a preference that makes queries easier to write and to read.
You might want to use IN or EXISTS, because your query is not returning columns from TableB.
Do not use unnecessary subqueries in the FROM clause. In some databases (notably MySQL), this impedes the use of indexes and adds additional overhead for materialization of the intermediate table.
And, the answer to your question is that the first version is probably the optimized version (because it does not materialize subqueries unnecessarily). Neither version is preferred.
First one is better in case of standard and performance but is very old fashioned so it can be written in this way
SELECT tableA.driver_id,tableA.vehicle_id
FROM tableA
INNER JOIN tableB ON tableA.driver_id=tableB.driver_id
AND tableA.vehicle_id=tableB.vehicle_id
AND tableA.driver_name='XYZ'
AND tableB.driver_name='XYZ'
AND tableA.is_allowed = 1

Not to used natural join

I was debate with my TL over natural join, he told natural join should not be used, so on what cases we are not going with natural join, equjoin and go with inner join.
Please rephrase your question like What are the implications between a Natural Join and Inner JOIN? 'What are the limitations of these JOINS in SQL Server 2008?
SQL Server gets rid of Natural Joins, so there also is a scalable aspect to their usage. Without getting too specific, a NATURAL JOIN is essentially like an INNER JOIN except it
A) returns distinct columns (think INTERSECT/UNION except tables can have differing columns)
B) add implicitly an EQUI JOIN on all of the available columns.
Illustration: Note, this was designed in SQL Server 2012
DECLARE #TableA TABLE (Col1 VARCHAR(10)
, Col2 VARCHAR(10) );
DECLARE #TableB TABLE (Col1 VARCHAR(10)
, Col2 VARCHAR(10)
, Col3 VARCHAR(10) );
INSERT INTO #TableA (Col1, Col2)
VALUES ('C', 'D');
INSERT INTO #TableB (Col1, Col2, Col3)
VALUES ('C', 'D', 'E');
SELECT *
FROM #TableA
NATURAL JOIN (SELECT Col1, Col2, Col3
FROM #TableB) AS B
-- returns
Col1 | Col2 | Co3
'C' 'D' 'E'
SELECT *
FROM #TableA AS A
INNER JOIN (SELECT Col1, Col2, Col3
FROM #Table B) AS B ON A.Col1 = B.Col1
AND A.Col2 = B.Col2
-- returns A = #TableA, B = #TableB
A.Col1 | B.Col1 | A.Col2 | B.Col2 | B.Col2
'C' 'C' 'D' 'D' 'E'
Do you see the difference? Rather significant, no? With the Inner you still could compare the two table's results, but a Natural JOIN is like a INTERCEPT, only it groups the columns together. You lose the relation in your result set.
Conclusion:
Everyone is entitled to their own opinion, but SQL will parse your query the same regardless.
Learning about how the joins work helps you understand what business use those joins can function...or at least work with other SQL languages.
TSQL removed the NATURAL JOIN in favor of UNION, UNION ALL, INTERSECT and EXCEPT.
If you can, ask your TL the 'whys' behind the business logic of using one or the other. Find out how he understands SQL Querying. You might either get something insightful or...well, be prepared to hear unconventional things...but at least you are learning more about SQL, your company, and how to ask questions.
A Win/Win, I say.

Cardinality violation when using a subquery that returns two values

I have create a sql query that the sketch is like this
select *
from A
where A.id in (select B.id1, B.id2 from B);
where the main select returns those values for which A.id coincides with either B.id1 or B.id2.
Clearly this solution doesn't work as the cardinality doesn't match in the where clause. How can I overcome this problem?
One solution would be to make two sub-queries, one for B.id1 and one for B.id2, but as my sub-query is much longer than in this example I was looking for a more elegant solution.
I'm using Mysql
EDIT 1
As long as the syntax is simpler than using two sub-queries I have no issues using joins
EDIT 2
Thanks #NullSoulException. I tried the first solution and works as expected!!
Something like the below should do the trick.
select *
From table1 a , (select id1 , id2 from table2 ) b
where (a.id = b.id1) or (a.id = b.id2)
or you can JOIN with the same table twice by giving the joined tables an alias.
select * from table1 a
INNER JOIN table2 b1 on a.id = b1.id1
INNER JOIN table2 b2 on a.id = b2.id2
Please test the above against your datasets/tables..

Update with nested subquery (sum) to get restricton on update clause

Got this bit of SQL as an update script, I've tried to add a work round to not being able to include the table to be updated as a clause in the statement so using sub queries, but struggling to get this to work.
Essientially I need update a vailue in table 1 with the summation of a field in table 2, but only where the two other fields match across a couple of tables and based on field6 the restriction is applied to the update clause.
UPDATE table1 W SET Field1=(SELECT field2 FROM
(SELECT A.id, B.field3, SUM(A.field2) AS field2
FROM table2 A, table3 B, table4 P
WHERE A.id=B.id AND P.field6=B.field6) B ) WHERE W.field6=B.field6
In the real world example, select the sum of points conceded in a rugby game when a rugby player has participated in the match. table 2 has the results (including the score) table 3 has the team sheets and table 1 and 4 are the same player table to be updated.
Hopefully this is clear enough and someone can point me in the right direction.
Tried the following:
UPDATE $WSLKEEP W, $WSLFIX A, $WSLFIXPLAY B
SET W.F_CONCEDED=SUM(A.F_AGAINST)
WHERE A.F_ID=B.F_GAMEID
AND B.F_NAME=W.F_NAME"
but now stuck with:
Invalid use of group function
Kind regards
It seems like your subquery should be grouping on field6 and exposing that column for inner join with table1. Here's how you do that in MySQL:
UPDATE table1 W
INNER JOIN (
SELECT B.field6, SUM(A.field2) AS field2
FROM table2 A, table3 B, table4 P
WHERE A.id=B.id AND P.field6=B.field6
GROUP BY B.field6
) B ON W.field6=B.field6
SET W.Field1 = B.Field2
And while we are at it, I would also recommend you to refrain from (ab)using comma joins in favour of explicit joins. The latter, however unusual at first after being long accustomed to a different syntax, can very soon become habitual and much more intuitive than the former. A great deal has been said on the topic, and some people may be holding quite strong opinions about comma joins. I say, comma joins can still have their share of use. However, when you are joining on a condition, the current ANSI syntax should be your choice.
Here's the above statement with the subquery transformed so as to use explicit joins:
UPDATE table1 W
INNER JOIN (
SELECT B.field6, SUM(A.field2) AS field2
FROM table2 A
INNER JOIN table3 B ON A.id = B.id
INNER JOIN table4 P ON P.field6 = B.field6
GROUP BY B.field6
) B ON W.field6 = B.field6
SET W.Field1 = B.Field2
For an update query like you have above, you are allowed to include multiple tables in the UPDATE clause, even if you aren't updating all of them. This will make sub-queries unnecessary and speed the execution quite a bit. For example, you can do something like this.
UPDATE table1 W, table2 A, table3 B, table4 P
SET W.Field1 = SUM(A.field2) ...
I'm unclear on the specifics of what you are trying to update exactly, but I just wanted to put out that you can often avoid sub-queries by using this kind of syntax.