Query showing all records of one table and adding new field - sql

So I have 3 tables which are:
Client = ClientID, ClientName,
Room = RoomID, RoomName
Booking = BookingID, RoomID, ClientID, Status (3 possible values: Booked, Checked-In, Checked-Out), CheckInDate, CheckOutDate
RoomID and ClientID has one-to-many relationship with the fields in booking table
My goal is to create a query that shows all of the rooms in the current time and show their status along with the information of the ocupant (if any) and their check in check out time of each room with these fields:
RoomStatus = RoomName, Status (4 possible values: Empty, Booked, Checked-In, Checked-Out (might be unnecessary since ocupant is no longer in the room)), ClientName, CheckInDate, CheckOutDate
I have managed to create simple query that using the relationships between the tables that shows all of the currently used room that shows all the information I needed. But the problem arise when I'm unable to show the unused room in the query. Since the status fields are in the booking table to keep it simple, the room table has no status field on its own to use.
I've attempted to make an empty query with showing all record of the room using the room id field and make new fields similar with the working ones that has null values and tried to left join and union it with the working one. However, left join only select similar record which only ends up showing the same thing as before and union provides duplicates. But I think this method to be "messy" if it does work.
So I'm open to any other method that is much better than my proposed method. Thank you very much.

I think this is what you are trying to achieve
select *
from #room c
left join
(
select b.*
from #Room r
inner join #Booking b on r.RoomID = b.RoomID
inner join #Client c on c.ClientID = b.ClientID
where CheckInDate = '02/03/2016'
) a on a.RoomID = c.RoomID
In MS Access this can be achived in 2 steps. 1st step will create Query which display result of this query.
select b.*
from #Room r
inner join #Booking b on r.RoomID = b.RoomID
inner join #Client c on c.ClientID = b.ClientID
where CheckInDate = '02/03/2016'
in second step you will do the left join on above QUERY with table rooms. Displaying All records from table room and only those records from above query where join matches.

Related

The SQL query succeeds, but does not make any changes to the table

I have the following problem. I run this request, which passes successfully but it says "0 (rows affected)". In short, what I want to do. I'm trying to write a query that adds elements to the main table because I've linked Child tables I'm trying to retrieve the IDs and put them in the main table
INSERT INTO Articles
([ID],
[ArtName],
[ArtType],
[SerNo],
[MACNo],
[UserID],
[Available],
[CityID],
[StoreID],
[WorkplaceID],
[ItemPrice],
[IP_01],
[IP_02],
[Note])
SELECT
(SELECT max([ID])+1 FROM Articles),
'HP',
art.ID,
'123',
'А18Н31',
u.ID,
av.ID,
c.ID ,
s.ID,
w.ID,
'14.23',
'192.168.11.3',
'192.168.11.3',
GetDate()
FROM Articles a
INNER JOIN Workplace w ON a.WorkplaceID = w.ID
INNER JOIN Store s ON a.StoreID = s.ID
INNER JOIN City c ON a.CityID = c.ID
INNER JOIN Avaiable av ON a.Available = av.ID
INNER JOIN Users u ON a.UserID = u.ID
INNER JOIN ArtType art ON a.ArtType = art.ID
WHERE c.CityName LIKE '%Sofia%' AND art.ArtTypeName LIKE '%FirstType%' AND s.StoreName LIKE '%First%' AND av.AvaiableName LIKE '%yes%' AND u.UserName LIKE '%Valq%' AND w.WorkplaceName LIKE '%FWorkplace%'
This says "0 rows affected" because the SELECT returns no rows. This could be because nothing matches the JOINs. This could be because the WHERE clause filters out all rows. Without sample data, there is no way to tell. You have to investigate yourself.
That said, this is highly suspicious:
(SELECT max([ID])+1 FROM Articles),
This is not the right way to have an incremental id in a table. You should be using an identity column. Or perhaps default to a sequence. In either case, the value of id would be set automatically when rows are inserted.
Also note that if this inserts multiple rows, all would get the same id, which is presumably not what you want.

Oracle sql query that returns customers who are coming for the first time in property

I have 3 tables: customer, property and stays. Table customer contains all the data about customers (customer_id, name, surname, email...). Table property contains the list of all the properties (property_id, property_name...) and table stays contains all the earlier stays of customers (customer_id, property_id, stay_id, arrival_date, departure_date...).
Some customers stayed multiple times in more than one properties and some customers are coming for the first time.
Can someone please explain oracle sql query which returns only the customers who are stying in any of the properties for the first time.
Sorry guys for answering late..
This is what I got so far.
Tables:
Customer $A$
Stays $B$
Property $C$
Customer_Fragments $D$
SELECT a.RIID_,
sub.CUSTOMER_ID_,
sub.PROPERTY_ID,
b.ARRIVAL_DATE,
c.PROPERTY_SEGMENT,
ROW_NUMBER() OVER (
PARTITION BY sub.CUSTOMER_ID_,
sub.PROPERTY_ID
ORDER BY
sub.CUSTOMER_ID_ asc
) RN
FROM
(
SELECT
b.CUSTOMER_ID_,
b.PROPERTY_ID
FROM
$B$ b
GROUP BY
b.CUSTOMER_ID_,
b.PROPERTY_ID
HAVING
COUNT(*)= 1
) sub
INNER JOIN $A$ a ON sub.CUSTOMER_ID_ = a.CUSTOMER_ID_
INNER JOIN $B$ b ON sub.CUSTOMER_ID_ = b.CUSTOMER_ID_
INNER JOIN $C$ c ON sub.PROPERTY_ID = c.PROPERTY_ID
LEFT JOIN $D$ d ON a.RIID_ = d.RIID_
WHERE
b.ARRIVAL_DATE = TRUNC(SYSDATE + 7)
AND c.PROPERTY_DESTINATION = 'Destination1'
AND lower(c.NAME_) NOT LIKE ('unknown%')
AND a.NWL_PERMISSION_STATUS = 'I'
AND a.EMAIL_DOMAIN_ NOT IN ('abuse.com', 'guest.booking.com')
AND (d.BLACKLISTED != 'Y'
or d.BLACKLISTED is null
)
I want to select all customers who will come to Destination1, 7days from today to inform them about some activities. Customers can book several
properties in Destination1 and have the same arrival date (example: I can book a room in property1 for me and my wife and also book a room in property2 for my friends.. and we all come to destination1 on the same arrival date).
When this is the case I want to send just one info email to a customer and not two emails. The above SQL query returns two rows when this is the case and I want it to return just one row (one row = one email).
It is always required to post a code you have already tried to write so that we can than help you with eventual mistakes.
After that being said, I'll try to help you nevertheless, writing the full code.
Try this:
select cus.*
from customers cus
join stays st
on st.customer_id = cus.customer_id
where st.arrival_date >= YOUR_DATE --for example SYSDATE or TRUNC(SYSDATE)
and 1 = (select count(*)
from stays st2
where st2.customer_id = cus.customer_id)
You haven't specified it, but I GUESS that you are interested in getting the first-time-customers whose arrival date will be at or after some specified date. I've written that into my code in WHERE clause, where you should input such a date.
If you remove that part of the WHERE clause, you'll get all the customers that stayed just once (even if that one and only stay was 10 years ago, for example). What's more, if you remove that part of the code, you can than also remove the join on stays st table from the query too, as the only reason for that join was the need to have access to arrival date.
If you need explanations for some other parts of the code too, ask in the comments for this answer.
I hope I helped!
WITH first_stays (customer_id, property_id, first_time_arrival_date, stay_no) AS
(
SELECT s.customer_id
, s.property_id
, s.arrival_date AS first_time_arrival_date
, ROW_NUMBER() OVER (PARTITION BY s.customer_id, s.property_id ORDER BY s.arrival_date) stay_no
FROM stays s
)
SELECT c.surname AS customer_surname
, c.name AS customer_name
, p.property_name
, s.first_time_arrival_date
FROM customer c
INNER
JOIN first_stays s
ON s.customer_id = c.customer_id
AND s.stay_no = 1
INNER
JOIN property p
ON p.property_id = s.property_id
The first part WITH first_stays is a CTE (Common Table Expression, called subquery factoring in Oracle) that will number the stays for each pair (customer_id, property_id) ordered by the arrival date using a window function ROW_NUMBER(). Then just join those values to the customer and property tables to get their names or whatever, and apply stay_no = 1 (first stay) condition.
If I understand the question correctly, this is not a complicated query:
select c.*
from c join
(select s.customer_id
from stays s
group by s.customer_id
having count(*) = 1
) s
on s.customer_id = c.customer_id;

SQL query not returning Null-value records

I am using SQL Server 2014 on a Windows 10 PC. I am sending SQL queries directly into Swiftpage’s Act! CRM system (via Topline Dash). I am trying to figure out how to get the query to give me records even when some of the records have certain Null values in the Opportunity_Name field.
I am using a series of Join statements in the query to connect 4 tables: History, Contacts, Opportunity, and Groups. History is positioned at the “center” of it all. They all have many-to-many relationships with each other, and are thus each linked by an intermediate table that sits “between” the main tables, like so:
History – Group_History – Group
History – Contact_History – Contact
History – Opportunity_History – Opportunity
The intermediate tables consist only of the PKs in each of the main tables. E.g. History_Group is only a listing of HistoryIDs and GroupIDs. Thus, any given History entry can have multiple Groups, and each Group has many Histories associated with it.
Here’s what the whole SQL statement looks like:
SELECT Group_Name, Opportunity_Name, Start_Date_Time, Contact.Contact, Contact.Company, History_Type, (SQRT(SQUARE(Duration))/60) AS Hours, Regarding, HistoryID
FROM HISTORY
JOIN Group_History
ON Group_History.HistoryID = History.HistoryID
JOIN "Group"
ON Group_History.GroupID = "Group".GroupID
JOIN Contact_History
ON Contact_History.HistoryID = History.HistoryID
JOIN Contact
ON Contact_History.ContactID = Contact.ContactID
JOIN Opportunity_History
ON Opportunity_History.HistoryID = History.HistoryID
JOIN Opportunity
ON Opportunity_History.OpportunityID = Opportunity.OpportunityID
WHERE
( Start_Date_Time >= ('2018/02/02') AND
Start_Date_Time <= ('2018/02/16') )
ORDER BY Group_NAME, START_DATE_TIME;
The problem is that when the Opportunity table is linked in, any record that has no Opportunity (i.e. a Null value) won’t show up. If you remove the Opportunity references in the Join statement, the listing will show all history events in the Date range just fine, the way I want it, whether or not they have an Opportunity associated with them.
I tried adding the following to the WHERE part of the statement, and it did not work.
AND ( ISNULL(Opportunity_Name, 'x') = 'x' OR
ISNULL(Opportunity_Name, 'x') <> 'x' )
I also tried changing the Opportunity_Name reference up in the SELECT part of the statement to read: ISNULL(Opportunity_Name, 'x') – this didn’t work either.
Can anyone suggest a way to get the listing to contain all records regardless of whether they have a Null value in the Opportunity Name or not? Many thanks!!!
I believe this is because a default JOIN statement discards unmatched rows from both tables. You can fix this by using LEFT JOIN.
Example:
CREATE TABLE dataframe (
A int,
B int
);
insert into dataframe (A,B) values
(1, null),
(null, 1)
select a.A from dataframe a
join dataframe b ON a.A = b.A
select a.A from dataframe a
left join dataframe b ON a.A = b.A
You can see that the first query returns only 1 record, while the second returns both.
SELECT Group_Name, Opportunity_Name, Start_Date_Time, Contact.Contact, Contact.Company, History_Type, (SQRT(SQUARE(Duration))/60) AS Hours, Regarding, HistoryID
FROM HISTORY
LEFT JOIN Group_History
ON Group_History.HistoryID = History.HistoryID
LEFT JOIN "Group"
ON Group_History.GroupID = "Group".GroupID
LEFT JOIN Contact_History
ON Contact_History.HistoryID = History.HistoryID
LEFT JOIN Contact
ON Contact_History.ContactID = Contact.ContactID
LEFT JOIN Opportunity_History
ON Opportunity_History.HistoryID = History.HistoryID
LEFT JOIN Opportunity
ON Opportunity_History.OpportunityID = Opportunity.OpportunityID
WHERE
( Start_Date_Time >= ('2018/02/02') AND
Start_Date_Time <= ('2018/02/16') )
ORDER BY Group_NAME, START_DATE_TIME;
You will want to make sure you are using a LEFT JOIN with the table Opportunity. This will keep records that do not relate to records in the Opportunity table.
Also, BE CAREFUL you do not filter records using the WHERE clause for the Opportunity table being LEFT JOINED. Include those filter conditions relating to Opportunity instead in the LEFT JOIN ... ON clause.

Get Data from 5 tables

i have 5 tables contains city information (Unite contain (but not always) sub unites - sub unites contain (but not always) building - and building contain (but not always) rooms
1-Unites: includes columns:
Id (PK)
UniteName
....
2- SubUnites: includes columns:
ID (PK)
Name
UniteId(FK for ID in Unites table Table)- Note (not all unite contain sub unite)
....
3- Building: includes columns:
ID (PK)
Name
SubUniteId (FK for ID in SubUnites Table)- Note (not all unite sub unite contain buildings)
...
4- Rooms: includes columns :
ID (PK)
Name
BuildingId (FK for ID in Building Table)- Note (not all building contain rooms)
....
5- Orders : includes columns:
ID
AreaId (which may be (ID column from Unite table) or (ID column from SubUnites table) or (ID column from Building table) or (ID column from Rooms table)
i can make order for for any of them by its ID
question :
how i can make sql select query to get orders for any of them with full information .. which mean if i get orders for a specif room i need to know in which building and in which sub unite and in which unite
and if i get orders for a specific building i need to know in which sub untes and in which unites an so on- with out duplicating data
i tried many queries but not working
any help
So it looks like you are trying to have a table [Orders] which is going to link/ relate to potentially 4 other tables via the [AreaId] column.
The problem is you haven't provided either a column to specify which table you are relating to for each particular order record.
Split the [Orders] table into 4 separate Orders tables with an order for each or provide a means, i.e. [UniteOrders], [SubUniteOrders], etc. Making each a one-unit to many orders relationship
Then if you want all orders, you could do a Union query to pull from all the tables
Another option would be to use GUIDs as the IDs and then you could store them in the [AreaId] and be certain to a high degree there would be no duplicates.
SQL Server doc on GUID type:
https://msdn.microsoft.com/en-us/library/ms187942.aspx
Ill give this a shot with out having access to the data. Please let me know if this is what you're trying to accomplish.
Select
U.ID
, U.NAME
, U.UniteName
, O_FROM_U.*
, SU.ID
, SU.NAME
, SU.UniteID
, O_FROM_SU.*
, B.ID
, B.Name
, B.SubUniteID
, O_FROM_B.*
, R.ID
, R.Name
, R.BuildingID
, O_FROM_R.*
FROM
Unites U
LEFT OUTER JOIN SubUnites SU ON SU.UNITEID = U.ID
LEFT OUTER JOIN Building B ON B.SubUniteID = SU.ID
LEFT OUTER JOIN Rooms R ON R.BuildingID = B.ID
LEFT OUTER JOIN ORDERS O_FROM_U ON U.ID = O_FROM_U.AreaID
LEFT OUTER JOIN ORDERS O_FROM_SU ON SU.ID = O_FROM_SU.AreaID
LEFT OUTER JOIN ORDERS O_FROM_B ON B.ID = O_FROM_B.AreaID
LEFT OUTER JOIN ORDERS O_FROM_R ON R.ID = O_FROM_R.AreaID
SELECT A.ID as unitid,A.Unitname as unitname,B.id as subuniteid,B.Name as subunitname,c.ID as buildingid,C.Name as buildingname,D.id as roomid,D.name as roomname,e.id as orderid,e.areaid
from
UniT A JOIN Subunit B
on A.Id=B.UnitId
Join Building c
on B.ID=C.Subunitid
Join Room D
ON C.ID=D.buildingid
Join Orders E
on E.Id=A.Id

SQL Server Return 1 Row Per Boat

Basically, what I want to do is join 4 tables together and return 1 row for each boat.
Table Layouts
[Boats]
id, date, section, raft
[Photos]
id, boatid, pthurl, purl
[River_Company]
id, sort, company, company_short
[River_Section]
id, section
Its very simple as far as structure, however, I've having the time of my life trying to get it to return only 1 row. No boat will ever be on the same day, the only thing that's messing this up is the photo table.
If you know a better way for it to return the record table for all the boats boats and only 1 photo from the photo table, please, please post it!!
Desired Format
boats.id, boats.date, river_company.company, river_section.section, photos.purl, photos.pthurl
It's basically how joins work. Since boats and photos are in one-to-many relationships and you want one-to-one-like query, you need to explicitly express it with predicate. For example:
select b.*
from
boats b
inner join photos p
on b.id = p.boatid
where p.id = (select max(id) from photos where boatid = b.id)
Assuming your ID column is the relation that you have designed:
SELECT Boats.* FROM Boats
LEFT OUTER JOIN Photos on Photos.ID =
(
SELECT TOP 1 Photos.ID FROM Photos
INNER JOIN Boats ON Photos.BoatID = Boats.ID
)
INNER JOIN River_Company on River_Company.ID = Boats.ID
INNER JOIN River_Section on River_Section.ID = Boats.ID
So basically, this will:
Guarantee the maximum row count of 1. (It's a bit dirty, but fact is if you have more than one photo, more than one link will be returned otherwise)
If there are no photo's, the boat will still be returned