sql server join 3 tables, not in other column of third table - sql-server

So, i have two tables which are connected by a third one.
Something like:
First Table:
+------------+--------------+--------------+------------+
| box_column | code_column | from_column | to_column |
+------------+--------------+--------------+------------+
| 12345 | sdsad1 | madrid | london |
+------------+--------------+--------------+------------+
Second Table:
+-------------+--------------+
| code_column | truck_column |
+-------------+--------------+
| sdsad1 | truck1 |
| sdsad1 | truck2 |
| sdsad1 | truck3 |
+-------------+--------------+
Third Table:
+--------------+-------------+-----------+
| truck_column | from_column | to_column |
+--------------+-------------+-----------+
| truck1 | madrid | paris |
| truck2 | paris | calais |
| truck3 | calais | london |
+--------------+-------------+-----------+
after having a join, just having the number of the box, is there any way i can distinct the trucks that make the last leg (third table have london in the to_column) and the others?

That is not very difficult to do, it's actually quite basic:
SELECT *
FROM dbo.code c
INNER JOIN dbo.jointable j on c.code = j.code
INNER JOIN dbo.truck t on j.truck = t.truck
WHERE c.box = 12345
AND c.[to] = t.[to]
Where code is your first table, jointable is your second table, and truck is your third table.
The output of this query is:
box code from to code truck truck from to
---------------------------------------------------------------------
12345 sdsad1 madrid london sdsad1 truck3 truck3 calais london
To get only the truck as output, replace
SELECT *
with
SELECT t.truck
Last but not least: I'm not seeing any primary keys, nor foreign keys in your model. Maybe you left it out. If not, please use keys and constraints.

Related

Track changes made in a record and get the version of the record at the given point of time in SQL Server

I need to track chages made in a record and able to get the any version of the record at given point of time.
Consider, I have the following contact table.
--------------------------
| contact |
--------------------------
| id |
| name |
| phone |
| email |
| city |
| country |
| create_by |
| created_at |
--------------------------
I want to achieve following things on the above table.
I want to track all the changes made in the records over the time.
I want to find the version of the record at the given point of time.
The original record should stay as it is (without any update).
For example,
So, I have created following table to track all the changes.
--------------------------
| contact_history |
--------------------------
| contact_id |
| field_name |
| old_value |
| new_value |
| modified_by |
| modified_at |
--------------------------
With this data model,
To create a new contact record, we will create the record in the contact table.
To Update a record, we will create a new record in the contact_history record with the field name, new value, current time and who modified the record.
In this way I can able to track, what change was made and who made the change and the same time the original record will stay as it is without any change.
What I am trying to achieve is to find the version of all the contact records at a given point of time.
For example, consider the following record.
Contact table
------------------------------------------------------------------------------------------------
| id | name | phone | email | city | country | created_by | created_at |
------------------------------------------------------------------------------------------------
| 1 | Steve | 1111111 | steve#abc.com | NY | USA | John | 2019-04-01 13:17:49.417 |
------------------------------------------------------------------------------------------------
Each update will be created as a history record in the contact_history table.
contact_history
-------------------------------------------------------------------------------------------------------
| contact_id | field_name | old_value | new_value | modified_at | modified_by |
-------------------------------------------------------------------------------------------------------
| 1 | email | steve#abc.com | steve#changed.com | 2019-04-02 08:19:49.213 | Arnold |
| 2 | city | NY | LA | 2019-04-03 12:48:37.568 | John |
| 3 | city | LA | SF | 2019-04-04 25:25:19.715 | John |
-------------------------------------------------------------------------------------------------------
When I need the version of the contact record before 2019-04-02 I should able to get the following,
------------------------------------------------------------------------------------------------
| id | name | phone | email | city | country | created_by | created_at |
------------------------------------------------------------------------------------------------
| 1 | Steve | 1111111 | steve#abc.com | NY | USA | John | 2019-04-01 13:17:49.417 |
------------------------------------------------------------------------------------------------
When I need the version of the contact record before 2019-04-03 I should able to get the following,
----------------------------------------------------------------------------------------------------
| id | name | phone | email | city | country | created_by | created_at |
----------------------------------------------------------------------------------------------------
| 1 | Steve | 1111111 | steve#changed.com | NY | USA | John | 2019-04-01 13:17:49.417 |
----------------------------------------------------------------------------------------------------
When I wanted the latest version of the same record I should able to get,
----------------------------------------------------------------------------------------------------
| id | name | phone | email | city | country | created_by | created_at |
----------------------------------------------------------------------------------------------------
| 1 | Steve | 1111111 | steve#changed.com | SF | USA | John | 2019-04-01 13:17:49.417 |
----------------------------------------------------------------------------------------------------
The example is given for only one record. It can be applicable for multiple contact records.
How can I write a efficient query to achieve this in SQL Server.
Simple. Use a TOP 1 query to get the most recent record before the date you want to filter on.
Unfortunately, due to the data model you've chosen to use, you'll need to do a TOP 1 subquery for every field in your result set that can be in your history table.
SELECT id,
(SELECT TOP 1 new_value ... WHERE field_name='Name' ... ) AS Name,
etc...

how to draw data from multiple tables?

I have 2 different tables. I need to get a name from the TMK table in table 1 as below, and I need to bring the total number from my 2nd table. I can't write join. can u help me
TMK Table;
| tmkName |
| George |
| Jacob |
flowNewStatus Table;
|statusId|
| 1 |
| 2 |
if george has number 1 status i want this join
| tmkName | |statusId|
| George | | 1 |
Before getting to possible SQL queries... from the tables you show you'd need an additional table that associates the person to status, a join table. Essentially a TMK_status table:
TMK_status table
| personID | statusID |
|----------|----------|
| 1 | 1 |
| 2 | 3 |
| 3 | 1 |
Alternatively, the statusID could be stored as a column of TMK thus,
TMK table
| personID | tmkName | statusID |
|----------|----------|----------|
| 1 | George | 1 |
| 2 | Jacob | 3 |
If by "I can't write join", you mean you don't know how, check this answer: What is the difference between "INNER JOIN" and "OUTER JOIN"? - you will need an inner join.
If, on on the other hand, you mean you can't use join statements, then you could write a subselect statement. There could be other solutions but they depend on how you decide to join/relate the 2 tables.

T-SQL Query which only displays rows where the value in one column matches the value in another column on another row

Having exhausted my limited knowledge of tsql I hope someone may be able to help?
I have a table which holds relationship data such as ID, name, relationship and reciprocal relationship type, start and finish date etc.
Each row contains the Reciprocal ID for the other side of the relationship. See below.
From that I would like to present rows where the ID is equal to 1234 and 1236.
Thank you in advance for help with this.
Paul
+------+-------+------------+------------+----------+------------+---------+
| ID | Name | Start | Finish | Type | Recip Type | RecipID |
+------+-------+------------+------------+----------+------------+---------+
| 1234 | Joe | 01/05/2018 | | Father | Daughter | 1235 |
+------+-------+------------+------------+----------+------------+---------+
| 1235 | Emily | 01/05/2018 | | Daughter | Father | 1234 |
+------+-------+------------+------------+----------+------------+---------+
| 1236 | Susan | 01/09/2017 | 01/05/2018 | Visitor | Patient | 1237 |
+------+-------+------------+------------+----------+------------+---------+
| 1237 | Harry | 01/09/2017 | 01/05/2018 | Patient | Visitor | 1236 |
+------+-------+------------+------------+----------+------------+---------+
Are you looking for or:
select t.*
from t
where id in (1234, 1236) or recipid in (1234, 1236);
Perhaps this would do what you intend:
select t1.*
from table t1
where exists (select 1 from table t2 where t1.id = t2.recipid);
However, same could be also achieve via self join

ISNULL/COALESCE for multiple fields

Consider the following data model:
Customers
CustNum | First Name | Last Name
555 John Doe
CustomerAddresses
CustNum | ShippingAddress| Line1 | Line2 | City | State | Zip
555 | ADD1 | 333 A Dr. | Apt. 10 | Dallas | TX | 11345
555 | ADD2 | 111 B St. | NULL | Miami | FL | 22222
555 | WXYZ | 123 Main St. | NULL | Detroit | MI | 99998
OrderHeader
OrdNum | CustNum | OrderTotal | Line1 | Line2 | City | State| Zip
1000 | 555 | 67.00 | 123 Main St. | Ste 1 | Detroit | MI | 99998
OrderLine
OrderNo | Item | Price | ShippingAddress
1000 | X123 | 32.00 | ADD1
1000 | Y234 | 25.00 | ADD2
1000 | ZZZZ | 10.00 | NULL
There is a one-to-many relationship between Customers and CustomerAddresses.
Each OrderHeader, instead of a key relationship to the CustomerAddresses table, stores the address used for shipping in the Line1, Line2, City, State, and Zip fields.
In addition, it's possible to select a shipping address in the OrderLine table that overrides the address stored in the OrderHeader.
I'm trying to come up with a query to return data in the following format, to generate a list of mailing labels:
MailingLabels
OrderNo | Item | Line1 | Line2 | City | State | Zip
1000 | X123 | 333 A Dr. | Apt. 10 | Dallas | TX | 11345
1000 | Y234 | 111 B St. | NULL | Miami | FL | 22222
1000 | ZZZZ | 123 Main St. | NULL | Detroit | MI | 99998
Basically, if the OrderLine record has a ShippingAddress value, I want to return the corresponding address from the CustomerAddresses table.
If it is NULL, then I want to return the Line1, Line2, City, State, and Zip values stored in the OrderHeader table.
The problem is, when I use COALESCE or ISNULL, it's possible to return incorrect results. Here's my query:
SELECT OH.OrderNo, Item, ISNULL(CA.Line1, OH.Line1), ISNULL(CA.Line2, OH.Line2),
ISNULL(CA.City, OH.City), ISNULL(CA.State, OH.State), ISNULL(CA.Zip, OH.Zip)
FROM OrderHeader OH
JOIN OrderLine OL
ON OH.OrderNo = OL.OrderNo
LEFT JOIN CustomerAddress CA
ON OL.CustNum = CA.CustNum
AND OL.ShippingAddress = CA.ShippingAddress
With the above query, if the Line2 field is defined for the OrderHeader, but the ShippingAddress is defined in OrderLine, it's possible to return a mixed address for the Y234 item:
OrderNo | Item | Line1 | Line2 | City | State | Zip
1000 | Y234 | 111 B St. | Ste 1 | Miami | FL | 22222
Note, Ste 1 is not part of the address denoted in the OrderLine, it's actually part of the OrderHeader.
How can I write a query to return the data in the desired fashion? Any and all help is greatly appreciated!
Unfortunately, I can't think of a neat way to do this without being quite repetitive.
Assuming the OL aliases should have been CA:
SELECT OH.OrderNo, Item,
CASE WHEN OL.ShippingAddress IS NULL THEN OH.Line1 ELSE CA.Line1 END,
CASE WHEN OL.ShippingAddress IS NULL THEN OH.Line2 ELSE CA.Line2 END,
CASE WHEN OL.ShippingAddress IS NULL THEN OH.City ELSE CA.City END,
CASE WHEN OL.ShippingAddress IS NULL THEN OH.State ELSE CA.State END,
CASE WHEN OL.ShippingAddress IS NULL THEN OH.Zip ELSE CA.Zip END
FROM OrderHeader OH
JOIN OrderLine OL
ON OH.OrderNo = OL.OrderNo
LEFT JOIN CustomerAddress CA
ON OL.CustNum = CA.CustNum
AND OL.ShippingAddress = CA.ShippingAddress

Connecting two tables

I'm designing a database for a Cab/Taxi service. There's a table for taxi service details.
*cab_services*
+---------------------+
| SID | Name |
|---------------------|
| S001 | ABC Taxi |
| S002 | XYZ Cabs |
| S003 | MN Taxi |
| S004 | OP Cabs |
|_______|_____________|
And there's another table for locations.
locations
+-----------------------------------+
| LID | Code | Location |
|----------------|------------------|
| L001 | CO | Akarawita |
| L002 | CO | Angamuwa |
| L003 | CO | Batawala |
| L004 | CO | Avissawella |
| L005 | CO | Battaramulla |
| L006 | GQ | Ambepussa |
| L007 | GQ | Bemmulla |
| L008 | GQ | Biyagama |
| L008 | GQ | Alawala |
| L010 | GQ | Andiambalama |
| L011 | GQ | Biyagama IPZ |
| L012 | KT | Bellana |
| L013 | KT | Bolossagama |
| L014 | KT | Bombuwala |
| L015 | KT | Alutgama |
| L016 | KT | Alubomulla |
|_______|________|__________________|
Note that they are categorized according to districts. (CO, GQ, KT) Each district has multiple towns/cities.
A taxi service may be providing their service in multiple districts. And one district may have multiple taxi services. Its sort of a many to many scenario.
I'm trying to connect the cab_services table with the locations table. But I can't figure out how to.
I would have done something like this if only one service was in on district.
+-------+-------------+---------+
| SID | Name | Locs |
|-------+-------------+---------|
| S001 | ABC Taxi | CO |
|_______|_____________|_________|
But like I said before, a service can have many districts.
+-------+-------------+---------+
| SID | Name | Locs |
|-------+-------------+---------|
| S001 | ABC Taxi | CO, KT |
|_______|_____________|_________|
This would violate the 1NF.
I would want to be able to get results in a situation like say, if a user search using a Location name, he should get the cab services in that area.
What changes do I have to do in my database, table structure to accomplish this?
Please let me know if some part is confusing, I'll try my best to clarify it further. I'm pretty bad at explaining things. Thank you.
It seems your connecting table only needs to define the FK columns for the cab_services table and the locations table (i.e., Note what Oded states about duplication). So for example, if "ABC Taxi" is available in ALL "CO" locations then the connecting table would have the following records:
SID | LID
-----------
S001 | L001
S001 | L002
S001 | L003
S001 | L004
S001 | L005
You will have multiple entries on the connecting table.
SID Name Locs
-----------------------
S001 ABC Taxi CO
S001 ABC Taxi KT
This is still in 1NF, though you are duplicating data by having SID and Name in the table.

Resources