How to build nested query in codeigniter? - php

Hi below is the query to get count of different data from different tables.
select(
select count(*)
from teachers
where teacher_status = 1
)as teacher_count,
(
select count(*)
from students
where student_status = 1
)as students_count,
(
select count(*)
from housekeepers
where housekeeper_status = 1
)as housekeeping_count,
(
select count(*)
from students
where student_status = 1 and
gender = "Male"
) as total_male_student_count,
(
select count(*)
from students
where student_status = 1 and
gender = "Female"
) as total_female_student_count
Now i want to build this single query in codeigniter with the help of codeigniter builder class, so can someone guide me please..
Purpose of running single query is to minimize the database hit.
Thanks in advance..!!!

You can use: get_compiled_select
like this
$this->db->select('count(*) as count');
$this->db->from('teacher_status');
$teacher_status = $this->db->get_compiled_select();
$this->db->select("select($teacher_status)as teacher_count, ... ");
this->db ...
And use for others.

Related

SQL Use Subquery results with NOT IN

I can imagine that question exists in some way, but I haven't found what I was looking for.
I need to remove the found values from the result I'm getting in the main query.
Consider the following:
The mainquery:
SELECT idTable
FROM tblTables
WHERE NOT IN idTables = ( **SUBQUERY HERE** )
AND dtSeats >= 4
LIMIT 1;
The subquery:
SELECT idTable
FROM tblTables,tblReservation
WHERE tblTables.idTable = tblReservation.fiTable
AND fiTime = 1
AND dtResDate = "2020-06-16"
In the tblTables there are idTable and dtSeats.
In the tblReservation are fiTime and dtResDate.
The subquery can get up to three rows.
I need to get the first free table with the lowest number of seats possible.
Thanks for helping me out!
Having the DDL and some sample data would be helpful, but I think what you are looking for is a NOT EXISTS clause. It returns everything in the outer query that doesn't match with a record in the inner query.
SELECT idTable
FROM tblTables tt
WHERE NOT EXISTS (
SELECT NULL FROM tblReservation tr WHERE tt.idTable = tr.idTable AND
tr.dtResDate = '2020-06-16'
)
AND dtSeats >= 4
ORDER BY tt.dtSeats
LIMIT 1

How do I send a query to get the sum of the two tables?

I want to get the sum of the two tables.
1-1.hospital_payment_data table
1-2.hospital_payment_data table data
2-1.advenced_payment table
2-2 advenced_payment table data
I want result
However, sending the query as follows results.
SELECT COUNT(IF(treatment_fees_check_division = '선수금',
treatment_fees_check_division, NULL)) AS COUNT,
SUM(CASE WHEN treatment_fees_check_division = '선수금'
THEN treatment_fees_difference END) + SUM(advenced_amount
) AS if_treatment_fees_check_division,
SUM(advenced_amount) AS sum_init_amount
FROM
(
SELECT treatment_fees_check_division, treatment_fees_difference,
init_amount, advenced_amount
FROM hospital_payment_data , advenced_payment
)AS a
bad result
How do I fix the query? I'd like your posture, please.
Is this what you are looking for?
SELECT ( SELECT SUM(...) FROM t1 ... ) +
( SELECT SUM(...) FROM t2 ... ) AS sum_of_tables

MySQL query to grab ALL rows that contain duplicate value in "slug" column

This code is looking for the rows that contain the same value in "slug" column and grouping them if they are found more than once.
UPDATED CODE:
$sql = " SELECT *,
COUNT(slug)
FROM cars
GROUP BY slug
HAVING ( COUNT(slug) > 1 )";
$q = $this->db->query($sql);
return $q;
The problem is that instead of:
blue-volkswagen-2001
blue-volkswagen-2001
red-toyota-1989
red-toyota-1989
red-toyota-1989
green-mercedes-50
green-mercedes-50
I am getting this:
blue-volkswagen-2001
red-toyota-1989
green-mercedes-50
Any idea what am I doing wrong and why only the first row is grabbed instead of all duplicates?
I have asked this question on CodeIgniter forum, but they didn't know how to do this so I can accept a custom SQL query from some SQl guru instead of Active Record, because that's probably not possible to achieve with Active Record.
You can use INNER JOIN with a subquery to achieve this.
$query = "SELECT a.*, b.total_count FROM cars a INNER JOIN (SELECT slug, count(*) as total_count FROM cars GROUP BY slug HAVING count(slug) > 1 ) b ON a.slug = b.slug WHERE b.total_count > 1";
$output = $this->db->query($query );
Do index slug column to improve performance.
This will give the output like the way you want.
Hope this helps :-)
Using subquery
SELECT * FROM `cars` WHERE slug IN ( SELECT slug FROM vehicle GROUP BY slug
HAVING ( COUNT(slug) > 1 ) )
SQLFIDDLE
SELECT MAX(slug)
FROM cars
GROUP BY slug
HAVING COUNT(slug) > 1

IF EXISTS do this.. stumped =x

So I want to insert into a table if there isn't an existing row matching conditions such as only allowing one "like" per 24-hours for the same product.
I have it nailed down to this so far, but now I need to take the hash and join in the id when making the insert. I've read that using DUAL doesn't allow joining in from other tables so I'm stumped here.
Any tips will be greatly appreciated :)
Thanks!
INSERT INTO platform.contentLikes
SELECT contents.contentId, 500000, NOW()
FROM DUAL
WHERE NOT EXISTS ( SELECT contentId, contents.contentId FROM platform.contentLikes
INNER JOIN platform.contents ON contents.hash = 'de9f21c14c1ab0bcca014825f8b09e76'
WHERE contentId = contents.contentId AND userId = 50000 )
INSERT INTO platform.contentLikes
SELECT rs.contentId, 500000, NOW()
FROM ( SELECT contents.contentId
FROM platform.contents LEFT JOIN platform.contentLikes ON contentLikes.contentId = contents.contentId AND contents.hash = 'de9f21c14c1ab0bcca014825f8b09e76' AND userId = 50000
WHERE contentLikes.contentId IS NULL)
rs
another option would be to get the contentID in your php code, and create your insert query with the contentID coded in:
$sql = 'INSERT INTO platform.contentLikes
SELECT ' . $contentId . ', 500000, NOW()

Need help in optimising query

I have two tables - incoming tours(id,name) and incoming_tours_cities(id_parrent, id_city)
id in first table is unique, and for each unique row from first table there is the list of id_city - s in second table(i.e. id_parrent in second table is equal to id from first table)
For example
incoming_tours
|--id--|------name-----|
|---1--|---first_tour--|
|---2--|--second_tour--|
|---3--|--thirth_tour--|
|---4--|--hourth_tour--|
incoming_tours_cities
|-id_parrent-|-id_city-|
|------1-----|---4-----|
|------1-----|---5-----|
|------1-----|---27----|
|------1-----|---74----|
|------2-----|---1-----|
|------2-----|---5-----|
........................
That means that first_tour has list of cities - ("4","5","27","74")
AND second_tour has list of cities - ("1","5")
Let's assume i have two values - 4 and 74:
Now, i need to get all rows from first table, where my both values are in the list of cities. i.e it must return only the first_tour (because 4 and 74 are in it's list of cities)
So, i wrote the following query
SELECT t.name
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id
AND tc0.id_city = '4'
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id
AND tc1.id_city = '74'
And that works fine.
But i generate the query dynamically, and when the count of joins is big (about 15) the query slowing down.
i.e. when i try to run
SELECT t.name
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id
AND tc0.id_city = '4'
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id
AND tc1.id_city = '74'
.........................................................
JOIN `incoming_tours_cities` tc15 ON tc15.id_parrent = t.id
AND tc15.id_city = 'some_value'
the query run's in 45s(despite on i set indexes in the tables)
What can i do, to optimaze it?
Thanks much
SELECT t.name
FROM incoming_tours t INNER JOIN
( SELECT id_parrent
FROM incoming_tours_cities
WHERE id IN (4, 74)
GROUP BY id_parrent
HAVING count(id_city) = 2) resultset
ON resultset.id_parrent = t.id
But you need to change number of total cities count.
SELECT name
FROM (
SELECT DISTINCT(incoming_tours.name) AS name,
COUNT(incoming_tours_cities.id_city) AS c
FROM incoming_tours
JOIN incoming_tours_cities
ON incoming_tours.id=incoming_tours_cities.id_parrent
WHERE incoming_tours_cities.id_city IN(4,74)
HAVING c=2
) t1;
You will have to change c=2 to whatever the count of id_city you are searching is, but since you generate the query dynamically, that shouldn't be a problem.
I'm pretty sure this works, but a lot less sure that it is optimal.
SELECT * FROM incoming_tours
WHERE
id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=4)
AND id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=74)
...
AND id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=some_value)
Just an hint.
If you use the IN operator in a WHERE clause, you can hope that the short-circuit of operator AND may remove unnecessary JOINs during the execution for the tours that do not respect the constraint.
Seems like an odd way to do that query, here
SELECT t.name FROM `incoming_tours` as t WHERE t.id IN (SELECT id_parrent FROM `incoming_tours_cities` as tc WHERE tc.id_city IN ('4','74'));
I think that does it, but not tested...
EDIT: Added table alias to sub-query
I've written this query using CTE's and it includes the test data in the query. You'll need to modify it so that it queries the real tables instead. Not sure how it performs on a large dataset...
Declare #numCities int = 2
;with incoming_tours(id, name) AS
(
select 1, 'first_tour' union all
select 2, 'second_tour' union all
select 3, 'third_tour' union all
select 4, 'fourth_tour'
)
, incoming_tours_cities(id_parent, id_city) AS
(
select 1, 4 union all
select 1, 5 union all
select 1, 27 union all
select 1, 74 union all
select 2, 1 union all
select 2, 5
)
, cityIds(id_city) AS
(
select 4
union all select 5
/* Add all city ids you need to check in this table */
)
, common_cities(id_city, tour_id, tour_name) AS
(
select c.id_city, it.id, it.name
from cityIds C, Incoming_tours_cities tc, incoming_tours it
where C.id_city = tc.id_city
and tc.id_parent = it.id
)
, tours_with_all_cities(id_city) As
(
select tour_id from common_cities
group by tour_id
having COUNT(id_city) = #numCities
)
select it.name from incoming_tours it, tours_with_all_cities tic
where it.id = tic.id_city

Categories