MySQL View Creation - mysql

I have two tables:
parking_lot
id
name
parking_spot
id
parking_lot_id
available
I would like to create a view that looks like this:
parking_lot_view
id
name
num_spots_available
What would the query to create this view be for a MySQL DB?

If you need to create a view, first start by creating a Select SQL Statement joining whatever tables you need. Then you just add "CREATE VIEW AS" at the beginning and Execute.
In your specific case, this should do the trick (I assumed 'available' is an Integer that contains 0 for unavailable and 1 for available, since you do not specify that in your question):
CREATE VIEW parking_lot_view AS
select L.id, L.name, count(*) available_spots
from parking_lot L inner join parking_spot S on S.parking_lot_id = L.id
where S.available <> 0
group by L.id, L.name

This is a simple query, so I assume you are pretty new to MySQL and databases. You should definitely try to understand how this works and study up on the subject:
create view parking_lot_view as
select pl.id, pl.name, sum(available) as NumAvailable
from parking_spot ps join
parking_lot pl
on ps.parking_lot_id = pl.id
group by pl.id, pl.name;
This assumes that available is 1 when available and 0 otherwise.

Related

SQL query optimization taking lot of time in execution

We have two tables one is properties and another one is property meta when we are getting data from one table "properties" , query only take less then one second in execution but when we are use join to get the data using bellow query from both tables its taking more then 5 second to fetch the data although we have only 12000 record in the tables , i think there is an issue in the sql query any help or suggestion will be appreciated.
SELECT
u.id,
u.property_title,
u.description,
u.city,
u.area,
u.address,
u.slug,
u.latitude,
u.longitude,
u.sync_time,
u.add_date,
u.is_featured,
u.pre_construction,
u.move_in_date,
u.property_status,
u.sale_price,
u.mls_number,
u.bedrooms,
u.bathrooms,
u.kitchens,
u.sub_area,
u.property_type,
u.main_image,
u.area_size as land_area,
pm7.meta_value as company_name,
pm8.meta_value as virtual_tour,
u.year_built,
u.garages
FROM
tbl_properties u
LEFT JOIN tbl_property_meta pm7
ON u.id = pm7.property_id
LEFT JOIN tbl_property_meta pm8
ON u.id = pm8.property_id
WHERE
u.status = 1
AND (pm7.meta_key = 'company_name')
AND (pm8.meta_key = 'virtual_tour')
AND (
(
( u.city = 'Delta'
OR u.post_code LIKE '%Delta%'
OR u.sub_area LIKE '%Delta%'
OR u.state LIKE '%Delta%')
AND country = 'Canada'
)
OR (
( u.city = 'Metro Vancouver Regional District'
OR u.post_code LIKE '%Metro Vancouver Regional District%'
OR u.sub_area LIKE '%Metro Vancouver Regional District%'
OR u.state LIKE '%Metro Vancouver Regional District%' )
AND country = 'Canada'
)
)
AND
u.pre_construction ='0'
GROUP BY
u.id
ORDER BY
u.is_featured DESC,
u.add_date DESC
Try adding this compound index:
ALTER TABLE tbl_property_meta ADD INDEX id_key (property_id, meta_key);
If it doesn't help make things faster, try this one.
ALTER TABLE tbl_property_meta ADD INDEX key_id (meta_key, property_id);
And, you should know that column LIKE '%somevalue' (with a leading %) is a notorious performance antipattern, resistant to optimization via indexes. (There's a way to create indexes for that shape of filter in PostgreSQL, but not in MariaDB / MySQL.)
Add another column with the meta stuff; throw city, post_code, sub_area, and state and probably some other things into it. Then build a FULLTEXT index on that column. Then use MATCH(..) AGAINST("Delta Metro Vancouver Regional District") in the WHERE clause _instead of the LEFT JOINs (which are actually INNER JOINs) and the really messy part of the WHERE clause.
Also, the GROUP BY is probably unnecessary, thereby eliminating extra sort on the intermediate set of rows.

MySQL DISTINCT returning not so distinct results

Good day,
I have a small issue with MySQL Distinct.
Trying the following query in my system :
SELECT DISTINCT `booking_id`, `booking_ticket`, `booking_price`, `bookingcomment_id`, `bookingcomment_message` FROM `mysystem_booking`
LEFT JOIN `mysystem_bookingcomment` ON `mysystem_booking`.`booking_id` = `mysystem_bookingcomment`.`bookingcomment_link`
WHERE `booking_id` = 29791
The point is that there are bookings like 29791 that have many comments added.
Let's say 10. Then when running the above query I see 10 results instead of one.
And that's not the way DISTINCT supposes to work.
I simply want to know if there are any comments. If the comment ID is not 0 then there is a comment. Of course I can add COUNT(blabla) as comment_number but that's a whole different story. For me now I'd like just to have this syntax right.
You may try aggregating here, to find which bookings have at least a single comment associated with them:
SELECT
b.booking_id,
b.booking_ticket,
b.booking_price
FROM mysystem_booking b
LEFT JOIN mysystem_bookingcomment bc
ON b.booking_id = bc.bookingcomment_link
WHERE
b.booking_id = 29791
GROUP BY
b.booking_id
HAVING
COUNT(bc.bookingcomment_link) > 0;
Note that depending on your MySQL server mode, you might have to also add the booking_ticket and booking_price columns to the GROUP BY clause to get the above query to run.
You can try below - using a case when expression
SELECT DISTINCT `booking_id`, `booking_ticket`, `booking_price`, `bookingcomment_id`,
case when `bookingcomment_message`<>'0' then 'No' else 'Yes' end as comments
FROM `mysystem_booking`
LEFT JOIN `mysystem_bookingcomment` ON `mysystem_booking`.`booking_id` = `mysystem_bookingcomment`.`bookingcomment_link`
WHERE `booking_id` = 29791

PostgreSQL find locks including the table name

I'm trying to take a look at locks that are happening on
specific tables in my PostgreSQL database.
I see there's a table called pg_locks
select * from pg_locks;
Which seems to give me a bunch of columns but is it possible
to find the relation because I see one of the columns is
the relation oid.
What table must I link that to to get the relation name?
This is Remy's query, adjusted for Postgres 10:
select nspname, relname, l.*
from pg_locks l
join pg_class c on (relation = c.oid)
join pg_namespace nsp on (c.relnamespace = nsp.oid)
where pid in (select pid
from pg_stat_activity
where datname = current_database()
and query != current_query());
If you just want the contents of pg_locks but with a human-friendly relation name,
select relation::regclass, * from pg_locks;
Try this :
select nspname,relname,l.* from pg_locks l join pg_class c on
(relation=c.oid) join pg_namespace nsp on (c.relnamespace=nsp.oid) where
pid in (select procpid from pg_stat_activity where
datname=current_database() and current_query!=current_query())
Remy Baron's answer is correct I just wanted to post one I came up
with as well only because it's more specific to what I need in this case
select pg_class.relname,
pg_locks.mode
from pg_class,
pg_locks
where pg_class.oid = pg_locks.relation
and pg_class.relnamespace >= 2200
;
The below command will give the list of locks:
select t.relname,l.locktype,page,virtualtransaction,pid,mode,granted
from pg_locks l, pg_stat_all_tables t where l.relation=t.relid
order by relation asc;

Add WHERE clause to single column

I have a query which I am working on, basically I have 3 columns:
Code: The users Code
Orders Taken: The orders which have been taken
Orders Taken From an External Call
Basically I just need a way to only allow Orders From External Calls to have a where clauses, when I add in my WHERE clause, it does it for both tables.
My query so far:
SELECT T_Temp_RestrictedDiaryCalls.AccreditedDomainCode,
Count(T_Temp_RestrictedProductSalesHistory.CustomerCode) AS [Orders Taken],
Count(T_Temp_RestrictedProductSalesHistory.CustomerCode) AS [Orders From External Calls]
FROM T_Temp_RestrictedDiaryCalls
INNER JOIN T_Temp_RestrictedProductSalesHistory
ON (T_Temp_RestrictedDiaryCalls.CustomerCode = T_Temp_RestrictedProductSalesHistory.CustomerCode)
AND (T_Temp_RestrictedDiaryCalls.CallDate = T_Temp_RestrictedProductSalesHistory.EntryDate)
GROUP BY T_Temp_RestrictedDiaryCalls.AccreditedDomainCode;
Any help will be greatly appreciated.
If I've got it right you should use CASE statement in the [Orders From External Calls] definition:
SELECT T_Temp_RestrictedDiaryCalls.AccreditedDomainCode,
Count(T_Temp_RestrictedProductSalesHistory.CustomerCode) AS [Orders Taken],
sum( CASE WHEN <Your condition here>
THEN 1
ELSE 0
END) AS [Orders From External Calls]
FROM T_Temp_RestrictedDiaryCalls
INNER JOIN T_Temp_RestrictedProductSalesHistory
ON (T_Temp_RestrictedDiaryCalls.CustomerCode = T_Temp_RestrictedProductSalesHistory.CustomerCode)
AND (T_Temp_RestrictedDiaryCalls.CallDate = T_Temp_RestrictedProductSalesHistory.EntryDate)
GROUP BY T_Temp_RestrictedDiaryCalls.AccreditedDomainCode;
Based on what you said on comments one column might have the count of all rows, and other column just show value on specify case.
So:
select table1.a,count(table1.b),
(select count(table2.c) from table2 where "where clause")
from table1
If I understand you correctly, you want both of those Orders columns to count data from the same table, but with different restrictions on which records from the table are counted and which are not. So do something like:
SELECT T_Temp_RestrictedDiaryCalls.AccreditedDomainCode,
Count(SalesHistoryForAllOrders.CustomerCode) AS [Orders Taken],
Count(SalesHistoryForExternalOrders.CustomerCode) AS [Orders From External Calls]
FROM T_Temp_RestrictedDiaryCalls
INNER JOIN T_Temp_RestrictedProductSalesHistory SalesHistoryForAllOrders
ON (T_Temp_RestrictedDiaryCalls.CustomerCode = SalesHistoryForAllOrders.CustomerCode)
AND (T_Temp_RestrictedDiaryCalls.CallDate = SalesHistoryForAllOrders.EntryDate)
INNER JOIN T_Temp_RestrictedProductSalesHistory SalesHistoryForExternalOrders
ON (T_Temp_RestrictedDiaryCalls.CustomerCode = SalesHistoryForExternalOrders.CustomerCode)
AND (T_Temp_RestrictedDiaryCalls.CallDate = SalesHistoryForExternalOrders.EntryDate)
GROUP BY T_Temp_RestrictedDiaryCalls.AccreditedDomainCode;
Explanation:
By INNER JOINing the table two times and aliasing it each time, we now have two separate representations of the table to work with (called SalesHistoryForAllOrders and SalesHistoryForExternalOrders).
You are then free to place a WHERE clause that refers to either one of them separately, and it will ONLY affect that column, not the other one. So either do:
WHERE SalesHistoryForExternalOrders.IsAnExternalOrder > 0
or just add an additional AND to the second INNER JOIN:
AND SalesHistoryForExternalOrders.IsAnExternalOrder > 0
, the result is the same: that clause will only be applied the External Calls column.

Correlated Subquery in a MySQL CASE Statement

Here is a brief explanation of what I'm trying to accomplish; my query follows below.
There are 4 tables and 1 view which are relevant for this particular query (sorry the names look messy, but they follow a strict convention that would make sense if you saw the full list):
Performances may have many Performers, and those associations are stored in PPerformer. Fans can have favorites, which are stored in Favorite_Performer. The _UpcomingPerformances view contains all the information needed to display a user-friendly list of upcoming performances.
My goal is to select all the data from _UpcomingPerformances, then include one additional column that specifies whether the given Performance has a Performer which the Fan added as their favorite. This involves selecting the list of Performers associated with the Performance, and also the list of Performers who are in Favorite_Performer for that Fan, and intersecting the two arrays to determine if anything is in common.
When I execute the below query, I get the error #1054 - Unknown column 'up.pID' in 'where clause'. I suspect it's somehow related to a misuse of Correlated Subqueries but as far as I can tell what I'm doing should work. It works when I replace up.pID (in the WHERE clause of t2) with a hard-coded number, and yes, pID is an existing column of _UpcomingPerformances.
Thanks for any help you can provide.
SELECT
up.*,
CASE
WHEN EXISTS (
SELECT * FROM (
SELECT RID FROM Favorite_Performer
WHERE FanID = 107
) t1
INNER JOIN
(
SELECT r.ID as RID
FROM PPerformer pr
JOIN Performer r ON r.ID = pr.Performer_ID
WHERE pr.Performance_ID = up.pID
) t2
ON t1.RID = t2.RID
)
THEN "yes"
ELSE "no"
END as pText
FROM
_UpcomingPerformances up
The problem is scope related. The nested Selects make the up table invisible inside the internal select. Try this:
SELECT
up.*,
CASE
WHEN EXISTS (
SELECT *
FROM Favorite_Performer fp
JOIN Performer r ON fp.RID = r.ID
JOIN PPerformer pr ON r.ID = pr.Performer_ID
WHERE fp.FanID = 107
AND pr.Performance_ID = up.pID
)
THEN 'yes'
ELSE 'no'
END as pText
FROM
_UpcomingPerformances up