Can we do a sql join with OR key word? - mysql

My table looks like as follows; (I populated it from excel)
I want to extract some data from another table so I use sql joins. Since my column contains comma separated values, i try to use join with Or but no success. Is this right way to do joins?
I look for quick solution for this comma separated columns.
eg:
SELECT * FROM test.types as a
inner join test.`matric as ma on (a.category= SUBSTRING_INDEX(ma.`Function Code AA`,',',1)
or a.category= SUBSTRING_INDEX(ma.`Function Code AA`,',',2)
or a.category= SUBSTRING_INDEX(ma.`Function Code AA`,',',3)
or a.category= SUBSTRING_INDEX(ma.`Function Code AA`,',',4)
or a.category= SUBSTRING_INDEX(ma.`Function Code AA`,',',5)
or a.category= SUBSTRING_INDEX(ma.`Function Code AA`,',',6))
and a.type = ma.`function Code NN` and ma.`Priority` = "T1"

You have a horrible data model. You probably cannot speed up the query very much. But you can at least simplify the code.
SELECT *
FROM test.types t JOIN
test.matric ma
ON FIND_IN_SET(t.category, REPLACE(ma.`Function Code AA`, ', ', ',')) > 0 OR
t.type = ma.`function Code NN`
WHERE ma.`Priority` = 'T1';
However, you should fix your data model!!!. Here are some issues:
Databases have very poor string processing capabilities.
Values should be stored using the correct type.
Foreign keys should be declared properly.
Such a structure prevents the database from using indexes, partitions, and the best optimization methods.
SQL has a great way to store lists. It is not called a string. It is called a table.

Related

MySQL can only use 61 tables in a join; How can I bypass this error for the following query?

I get a MySQL Error saying, I cannot use more than 61 tables in a join. I need to avoid this error. How do I do it? Please Help.
select
view_pdg_institutes.user_id as User_ID,
view_pdg_institutes.institute_id as Teacher_ID,
view_pdg_institutes.institute_name as Institute_Name,
view_pdg_institutes.user_email as Email,
view_pdg_institutes.contact_person_name as Contact_Person,
view_pdg_institutes.alternative_contact_no as Alternative_Mobile_No,
view_pdg_institutes.primary_contact_no as Mobile_No,
view_pdg_institutes.correspondance_address as Address,
view_pdg_institutes.other_communication_mode as Preferred_Contact_Mode,
view_pdg_institutes.size_of_faculty as Size_of_Faculty,
view_pdg_institutes.operation_hours_from as Operation_Hours_From,
view_pdg_institutes.operation_hours_to as Operation_Hours_To,
view_pdg_institutes.teaching_xp as Teaching_Experience,
view_pdg_institutes.installment_allowed as Installment_Allowed,
view_pdg_institutes.about_fees_structure as About_Fees_Structure,
view_pdg_institutes.no_of_demo_class as No_of_Demo_Classes,
view_pdg_institutes.demo_allowed as Demo_Allowed,
view_pdg_institutes.price_per_demo_class as Price_Per_Demo_Class,
view_pdg_tuition_batch.tuition_batch_id as Batch_ID,
view_pdg_batch_subject.subject_name as Subject_Name,
view_pdg_batch_subject.subject_type as Subject_Type,
view_pdg_batch_subject.academic_board as Academic_Board,
view_pdg_batch_fees.fees_type as Fees_Type,
view_pdg_batch_fees.fees_amount as Fees_Amount,
view_pdg_tuition_batch.course_days as Course_Days,
view_pdg_tuition_batch.days_per_week as Days_Per_Week,
view_pdg_tuition_batch.class_duration as Class_Duration,
view_pdg_tuition_batch.class_type as Class_Type,
view_pdg_tuition_batch.course_length as Course_Length,
view_pdg_tuition_batch.course_length_type as Course_Length_Type,
view_pdg_tuition_batch.no_of_locations as No_of_Locations,
view_pdg_tuition_batch.class_capacity_id as Class_Capacity_ID,
view_pdg_tutor_location.locality as Locality,
view_pdg_tutor_location.address as Address,
view_pdg_batch_class_timing.class_timing as Class_Timing
from view_pdg_tuition_batch
left join view_pdg_institutes on (view_pdg_tuition_batch.tutor_institute_user_id = view_pdg_institutes.user_id)
left join view_pdg_batch_subject on (view_pdg_batch_subject.tuition_batch_id = view_pdg_tuition_batch.tuition_batch_id)
left join view_pdg_batch_fees on (view_pdg_batch_fees.tuition_batch_id = view_pdg_tuition_batch.tuition_batch_id)
left join view_pdg_batch_class_timing on (view_pdg_batch_class_timing.tuition_batch_id = view_pdg_tuition_batch.tuition_batch_id)
left join view_pdg_tutor_location on (view_pdg_tutor_location.tuition_batch_id = view_pdg_tuition_batch.tuition_batch_id)
group by view_pdg_tuition_batch.tuition_batch_id;
I need a solution that would not require changing the current approach of writing the query.
I don't think it's possible to do what you're asking without some elaborate changes in the way you store and query data. You can
denormalize your DB to store JSON data;
create materialized views, emulating them via triggers, because they're absent in MySQL;
use temporary tables;
join partial selects by hand at the call site;
compile MySQL with another join limit;
use proper SQL engine like Postgres, that doesn't suffer from such stupid things.
Insert the contents of each view into its own temporary table. Then do the same query with the temporary table names substituted for the original view names.

Inner join on a partial column in Access

I'm attempting to join two tables in MS Access 2010 where the join condition is part of(A.col1) = B.col2. I've not been able to figure out how to do this so far.
My two tables have these critical columns:
Table 1 has column ICD9 Code-Description* with values like:842.00 - Sprain/strain, wrist924.11 - Contusion, knee
Table 2 has column Dx with values like:842924.11
I have tried these two join criteria:
FROM Table1
INNER JOIN Table2 ON Table1.Replace(LTrim(Replace(Left(ICD9Code-Description],
(InStr(1,[ICD9Code-Description]," "))-1),"0"," "))," ","0")
= Table2.Dx
and
SELECT ICD9
FROM Table2 INNER JOIN
(SELECT Replace(LTrim(Replace(Left([ICD9 Code-Description],
(InStr(1,[ICD9 Code-Description]," "))-1),"0"," "))," ","0") AS ICD9
FROM Table1)
ON Diag.DX = ICD9
Neither of which Access likes.
I'd like to avoid pulling out the join criteria portion into its own column in Table1 if at all possible.
What would be the Access way of doing this?
*Don't hate me for the column name. I didn't create it, I just have to support it.
The Val() function "Returns the numbers contained in a string as a numeric value of appropriate type." (See the Val Function help topic in Access' built-in help system.)
The "neat thing" for your situation is it reads characters from the string until it encounters a character which can't be part of a valid number. But then it doesn't throw an error. It just keeps the numeric characters it's already collected and ignores the rest.
Here's two of your examples in the Immediate window ...
? Val("842.00 - Sprain/strain, wrist")
842
? Val("924.11 - Contusion, knee")
924.11
So Val() should make your JOIN much simpler, even though you would need to also apply it on the Table2.Dx strings ...
FROM
Table1 INNER JOIN Table2
ON Val(Table1.[ICD9Code-Description]) = Val(Table2.Dx)

Is there a less verbose SQL query for matching two values against a single list of possibilities?

A web site I support executes a MySQL database query that looks like this:
SELECT
person_per.per_ID
FROM
person_per
LEFT JOIN
person_custom
ON
person_custom.per_ID=person_per.per_ID
where
(per_City='Cathedral City') or
(per_City='Cherry Valley') or
(per_City='Coachella') or
[...and so on for several dozen cities...];
The query is supposed to return the set of people who live in any of the specified list of cities. The query is ugly and verbose, but it works fine.
However, the new request is to modify the query so that it checks not only the person_per.per_City field but also the person_custom.work_City field as well, so that the query returns any one who either lives or works in any of the specified cities.
The naive way to do this would be to simply double the number of "or" clauses, like this:
SELECT
person_per.per_ID
FROM
person_per
LEFT JOIN
person_custom
ON
person_custom.per_ID=person_per.per_ID
where
(per_City='Cathedral City') or
(work_City='Cathedral City') or
(per_City='Coachella') or
(work_City='Coachella') or
[...and so on for several dozen cities...];
But I'd like to avoid doing it that way if possible, because the only thing worse then a 20-line SQL query containing the entire list of city-names is a 40-line SQL query containing the entire list of city-names twice. That query would be (even more) difficult to write and maintain.
So, is there a way to phrase this query-on-two-columns such that each city's name only appears once in the query? (I know I could create an SQL table of city names, but I'd rather not modify the applications' set of SQL tables if possible, so I'd prefer a solution that modifies only the SQL query itself)
You should use the IN operator to check if a value is in a list of other values, so the first query would be simplified to:
SELECT person_per.per_ID
FROM person_per
LEFT JOIN person_custom USING(per_ID)
WHERE per_City IN ( 'Cathedral City', 'Cherry Valley', 'Coachella', ... )
For the second query I would recommend either storing the list of cities in a table or a variable to reduce duplication. The table version of the query would look something like:
SELECT person_per.per_ID
FROM person_per
LEFT JOIN person_custom USING(per_ID)
WHERE per_City IN ( SELECT cities_City FROM cities )
OR work_City IN ( SELECT cities_City FROM cities )
As mentioned in the comments, use the "in" operator:
SELECT
person_per.per_ID
FROM
person_per
LEFT JOIN
person_custom
ON
person_custom.per_ID=person_per.per_ID
where
per_City in ('Cathedral City','Coachella', 'city1', 'city2', ...) OR
work_City in ('Cathedral City','Coachella', 'city1', 'city2', ...)
Comma seperated strings could be easily build up with every programing language, so you shouldn't have to much work on this.

How can I optimize this raw SQL and perhaps implement it via CodeIgniter?

It's been a while since I've written raw SQL, I was hoping someone could help me out in optimizing this SQL query so that it works across, both, MySQL and PostgreSQL.
I would also have to implement this via CodeIgniter (2.x) using ActiveRecord, any help/advice?
SELECT *
FROM notaries, contact_notaries
WHERE notaries.id = contact_notaries.notary_id
AND WHERE ( contact_notaries.city LIKE %$criteria%
OR contact_notaries.state LIKE %$criteria
OR contact_notaries.address LIKE %$criteria%)
Thanks!
Each query can have just one WHERE clause (you don't need the second)
It's much better to put join condition into JOIN rather then WHERE.
Are you sure you really need all the columns from 2 tables (*)?
So I'd refactor it to
SELECT [field_list]
FROM notaries
INNER JOIN contact_notaries ON (notaries.id = contact_notaries.notary_id)
WHERE ( contact_notaries.city LIKE '%$criteria%'
OR contact_notaries.state LIKE '%$criteria'
OR contact_notaries.address LIKE '%$criteria%')
Using a1ex07's query:
SELECT [field_list]
FROM notaries
INNER JOIN contact_notaries ON (notaries.id = contact_notaries.notary_id)
WHERE ( contact_notaries.city LIKE '%$criteria%'
OR contact_notaries.state LIKE '%$criteria'
OR contact_notaries.address LIKE '%$criteria%')
Active record:
$this->db->select(); // Leave empty to select all fields
$this->db->join('contact_notaries', 'notaries.id = contact_notaries.notary_id', 'inner');
$this->db->like('contact_notaries.city', 'criteria');
$this->db->like('contact_notaries.state', 'criteria');
$this->db->like('contact_notaries.address', 'match');
$results = $this->db->get('notaries');
To specify a list of fields you can do $this->db->select('field_1, field_2, ...');.
http://codeigniter.com/user_guide/database/active_record.html

Best way to reference an outer query / subquery?

I'm trying to reference a field from the 1st select table in the 3rd select(subquery) table.
However, that field isn't recognized when it goes to that sub-level of a query.
The php code I'm working on uses sql to return part of the sql command (string) that will be used in other places.
I've came up with this example that shows up the kind of nested querys that I want to solve.
In here I'm trying to get the name and emails of users that are working at night and have a matching job rank for an available job:
tables -----------> fields
table_users -> [user_id, name, email, rank, ...]
table_users_jobs -> [user_id, job_id, period, ....]
table_jobs -> [job_id, status, rank, ...]
-- sql calling code -> $rank = "t1.rank"; get_users_info_by_rank($rank);
-- maybe using: SET #rank = NULL; SELECT #rank := $rank, t1.name, ...
SELECT t1.name, t1.email
FROM table_users as t1
WHERE t1.user_id IN (
SELECT t2.user_id
FROM table_users_jobs as t2
WHERE t2.period = 'night' AND
t2.job_id IN (
-- avaiable jobs to that rank -> get_job_ranks_sql($rank);
SELECT t3.job_id
FROM table_jobs as t3
-- maybe using: t3.rank = #rank
WHERE t3.rank = t1.rank AND
t3.status = 'avaiable_position')
)
Working a little I guess I could avoid the 3rd level select problem. Nevertheless the point is that I'm trying to reuse sql code like the function that gives me the job_id of the rank that I chose:
function get_job_ranks_sql($rank){
//probably 't3' will be renamed for something more unique
return 'SELECT t3.job_id
FROM table_jobs as t3
WHERE t3.rank = '.$rank.' AND
t3.status = "available_position")';
}
Even using php I'm trying to make it generic to maybe use with another language if possible.
The sql version using is MySQL 5.1.41
Actually I think it's possible the way I want, by using sql variables like #rank, but I'm not sure if it's slower and if there are other better ways to do it.
Thanks in advance for any help :)
So, as one commenter pointed out, I think you would do much better off using JOINS, than sub-selects. For example, if I am reading your query/problem correctly, you could do a join query like this:
SELECT t1.name, t1.email, t3.job_id
FROM table_users t1
LEFT JOIN table_users_job t2
ON t1.user_id = t2.user_id
LEFT JOIN table_jobs t3
ON t3.job_id = t2.job_id
WHERE t2.period = 'night
AND t3.status = 'available_position'
Which is a lot more concise, easier to read, and is easier on your database. But doing this would prevent you from modularizing your SQL. If that is really important, you might consider storing such queries in Stored Procedure. This way, you can actually get a SP to return a list of results. Take a look at this tutorial:
http://www.wellho.net/resources/ex.php4?item=s163/stp4
Of course, that doesn't really solve your problem of being able to access variables at the lower levels of a sub select, but it would make your SQL easier to manage, and make it available to other language implementations, as you mentioned might be a need for you.
Something else to consider, in the bigger picture, would be migrating to a PHP framework that provides an ORM layer, where you could make those tables into objects, and then be able to access your data with much greater ease and flexibility (usually). But that is very 'big picture' and might not be suitable for your project requirements. One such framework that I could recommend, however, is CakePHP.