Joining a table to itself in django ORM - sql

I am creating a room booking system in Django and need a way to find overlaps in a reservation. I have come up with this raw query:
select distinct y.reservation_base_id as id
from app_reservation
x inner join app_reservation y on x.reservation_base_id != y.reservation_base_id
and x.id != y.id
and x.start <= y.stop
and y.start <= x.stop
where x.reservation_base_id = %s;
Here 'app_reservation' is an actual reservation that has the info about start and stop of the reservation. A reservation links to a reservation base.
A reservation base has meta information about the reservation ie: title, description.
This query works, however, I would like to translate it to Django orm so I can easily modify it, and make it more flexible. I have looked into sub-querying and Q-nodes, but I have not found a way to join a model to itself. Any help would be greatly appreciated.

Related

Display correct results in many to many relatonship tables

I currently have three tables.
master_tradesmen
trades
master_tradesmen_trades (joins the previous two together in a many-to-many relationship). The 'trade_id' and 'master_tradesman_id' are the foreign keys.
Here is what I need to happen. A user performs a search and types in a trade. I need a query that displays all of the information from the master_tradesmen table whose trade in the master_tradesmen_trade table matches the search. For example, if 'plumbing' is typed in the search bar (trade_id 1), all of the columns for Steve Albertsen (master_tradesman_id 6) and Brian Terry (master_tradesman_id 8) would be displayed from the master_tradesmen table. As a beginner to SQL, trying to grasp the logic of this is about to make my head explode. I'm hoping that someone with more advanced SQL knowledge can wrap their head around this much easier than I can. Note: the 'trades' column in master_tradesmen is for display purposes only, not for querying. Thank you so much in advance!
You have a catalog for the tradesmen, & another catalog for the trades.
The trades should only appear once in the trades catalog in order to make your DB more consistent
Then you have your many-to-many table which connects the trades & master tradesmen tables.
If we want to get the tradesmen according to the given trade in the input, we should first
know the id of that trade which has to be unique, so in your DB you would have something
like the img. below :
Now we can make a query to select the id of trade :
DECLARE #id_trade int = SELECT trade_id FROM trades WHERE trade_name LIKE '%plumbing%'
Once we know the trading id, we can redirect to the 'master_tradesmen_trades' table to know the name of the people how work that trade :
SELECT * FROM master_tradesmen_trades WHERE trade_id = #id_trade
You will get the following result :
You may say, 'But there is still something wrong with it, as i am still not able to see the tradesmen', this is the moment when we make an inner join:
SELECT * FROM master_tradesmen_trades trades_and_tradesmen
INNER JOIN master_tradesman tradesmen
ON tradesmen.id = trades_and_tradesmen.master_tradesmen_id
WHERE trade_id = #id_trade
IF you need to see specific columns, you can do :
SELECT first_name, last_name, city, state FROM master_tradesmen_trades trades_and_tradesmen
INNER JOIN master_tradesman tradesmen
ON tradesmen.id = trades_and_tradesmen.master_tradesmen_id
WHERE trade_id = #id_trade

Simple.Data - How to apply WHERE clauses to joined tables

I'm trying to use Simple.Data as my ADO, but I've run into a problem trying to put together a query that joins a couple of tables, then filters the results based on values in the non-primary tables.
Scenario is a job application app (but jobs are like a specific task to be done on a given day). There are 3 relevant tables, jobs, applications and application_history. The can be many applications for each record in the jobs tables, and many application_history records for each applications. In the application_history table, there's a status column as each application gets sent, offered and finally accepted.
So I want a query that returns all the accepted applications that are for jobs in the future; i.e. where the date column in the jobs table is in the future and where there's an associated record in the application_history table where the status column is 5 (meaning accepted).
If this was plain old SQL, I'd use this query:
SELECT A.* FROM application AS A
INNER JOIN application_history AS AH ON AH.application_id = A.id
INNER JOIN job AS J ON J.id = A.job_id
WHERE AH.status_id = 3 AND J.date > date('now')
But I want to know how to achieve the same thing using Simple.Data. For bonus points, if you could start by ignoring the 'job must be in the future' step, that will help me understand what's going on.
As a reference: Simple.Data documentation especially the part about explicit joins.
You should be able to do something like this:
//db is your Simple.Data Database object
db.application
.Join(db.application_history)
.On(db.application.id == db.application_history.application_id)
.Join(db.job )
.On(db.Applications.job_id == db.job.id)
.Where(db.application_history.status_id == 3 && db.job.date > DateTime.Now());
I'm not sure whether or not Simple.Data knows how to handle the Date part.

SQL Join Statement based on date range

New SQL dev here. I'm writing a call log application for our Asterisk server. In one table (CDRLogs), I have the call logs from the phone system (src, dst, calldate, duration). In another table I have (Employees) I have empName, empExt, extStartDate extEndDate). I want to join the two together on src and empExt based on who was using a particular ext on the date of the call. One user per extension in a given time frame.
For example, we have had 3 different users sitting at x100 during the month of July. In the Employees table, I have recorded the dates each of these people started and ended their use of that ext. How do I get the join to reflect that?
Thanks in advance
Perhaps something like:
SELECT A.*, B.*
FROM CDRLOGS A
INNER JOIN Employees B
ON A.SRC = B.EmpExt
AND A.CallDate between B.extStartDate and coalesce(B.extEndDate,getdate())
Please replace the * with relevant fields needed
and there may be a better way as a join on a between seems like it would possibly cause some overhead, but I can't think of a better way presently.

Complexity of inserting

My issue with an old customer plus outdated system.Part of issue. The 3 tables contain existing data in database. Let me explain, what was the scenario and then I hope you guys can help me get this job done.
Scenario :
There were a lot of Product, especially ProductZone, as you might imagine...
Customer add new Zone(let’s assume new Zone U,V,W,X,Y,Z),unfortunately did not for ProductZone!
Costomer need to update(insert) ProductZones to make all existing Products refer with new Zones and some older Zones(let’s assume older Zone R,S,T) if it didn't exist,here I came across...,need your help!
Explanation :
If i understand correctly i have to massive insert ProductZone and in this case by complicate T-SQL both filter condition and insert statement.
I'd be glad to take any suggestions,Thanks in advance.
This query will populate the Zones for existing products available in ProductZone Table and the new products available in Product table.
INSERT INTO ProductZone
SELECT ZoneNo,
ProductNo
FROM Product a
CROSS JOIN ZONE b
WHERE NOT EXISTS (SELECT 1
FROM ProductZone c
WHERE a.ProductNo = c.ProductNo
AND a.zone = c.zone)

SQL notes getting joined twice because they are related to service not unit

Ok I have a database that looks as follows:
Orders, Services, OrderUnits, Notes
Orders: id
Services: id, orderid
Units: id, Orderid, unitnumber
Notes: id, relatedid, text, date
Orders have 1 to many order units
Orders have 1 to many services
Services have 1 to many notes
I am trying to relate only the notes that relate to the unit and show those records, the problem is there is no database relation between notes and unit, only service and note.
I am trying to get the following:
select u.unitnumber
,n.date
,o.id
,s.id
,n.text
FROM tblorders o
INNER JOIN tblServices s on o.id = s.orderid
INNER JOIN tblUnits u on o.id = u.orderid
INNER JOIN tblNotes n on s.id = n.RelatedId
WHERE n.Text LIKE '<p>The status for the Unit # % has changed from % to OUTTOVENDOR</p>'
The problem here is that this gives me the 2 units 4 times if there is 2 units in the same service because the service is related to the note and not the unit.
The note does contain the unit number in it so I was wondering if I could do anything there to somehow relate the note to the unit number?
Thanks!
If at all possible, please rename your columns to be the same in every table. Don't call it just "ID" in the order table, call it OrderID (capitalization optional). Since RelatedID refers to the service table, change it to ServiceID instead, for crying out loud! This will save so much renaming and aliasing and incorrect joins and general all-around confusion. I promise you this.
If Notes are always about Units, they need to be linked to Units relationally through a column. You've simply got to add the column UnitID to the Notes table. Anything else is a horrible, performance-clobbering hack that will come back and haunt you.
Even adding UnitID to the Notes table is still not fully normalized because a Note could refer to a Service and a Unit that aren't for the same order. Would you please explain more about what Units and Services are and how they and Notes all relate to each other? I bet there's a way to fix it.
If notes should always be related to units, your best best is to fix the design not hack it up with something that will be a performance killer. Why can't you add a column for unitid, populate it once using the hack to get existing data and then have the user interface changed to add the unit id when it adds the note?
Incidentally you are using a text field and those are deprecated, you probably should look at changing it to a varchar(max) as soon as possible (this assumes you are on SQL Server 2005 or higher).
Do you need the order units? If you have orders related to services related to notes, the orders -> orderUnits relation will cause your recordset to increase exponentially, like you're seeing, because there isn't a direct relationship there.
Assuming that u.unitnumber is an integer:
select u.unitnumber
,n.date
,o.id
,s.id
,n.text
FROM tblorders o
INNER JOIN tblServices s on o.id = s.orderid
INNER JOIN tblUnits u on o.id = u.orderid
INNER JOIN tblNotes n on s.id = n.RelatedId
AND n.Text LIKE '<p>The status for the Unit # % has changed from % to OUTTOVENDOR</p>'
AND CAST(SUBSTRING(n.Text, 30, CHARINDEX(' ', n.Text, 30) - 30) AS int) = u.unitnumber