Subract and Add two columns from different table - sql

I want to subract and add two columns from different table.
table book:
BookID | BookName | Author | Edition | PublishingYear | copies| Shelf | Row
1 | SQL | Robert | 3 | 2005 | 3 | A |third
table Issue: (in this I have created join with tblPerson to show the PersonName instead of PersonID)
BookID | BookName | DateIssue | ReturnDate | PersonName | copies
1 | SQL | 2015-10-12 | 2015-10-12 | john | 1
table Return:
BookID | BookName | DateIssue | ReturnDate | PersonName | copies
1 | SQL | 2015-10-12 | 2015-10-12 | john | 1
Sql Query:
Select (tblBook.copies) - (tblIssue.copies)
FROm tblBook
FULL join tblIssue
ON tblBook.copies = tblIssue.copies
This query doesn't subract these two columns(copies).
I want to minus the column (copies) tblIssue from tblbook column copies(original value) when I issue the book.
And when I return the book from tbl Return, it gives me the original value in the column(copies) in tblBook.

When you are doing joins, you need to join tables on they keys that binds the tables togheter.
Joining two tables on copies makes no logical sense, so instead join it on the primary key foreign key references BookID.
Select (tblBook.copies) - (tblIssue.copies)
FROm tblBook
FULL join tblIssue
ON tblBook.BookId = tblIssue.BookId
This will produce a following result, if no negations whas made.
BookID | BookName | Author | Edition | PublishingYear | copies| Shelf | Row | BookID | BookName | DateIssue | ReturnDate | PersonName | copies
1 | SQL | Robert | 3 | 2005 | 3 | A |third| 1 | SQL | 2015-10-12 | 2015-10-12 | john | 1
Thereby subtracting 3-1 which should equal 2. But it is always important to consider what the join result should be and then plan out your join strategy.
EDIT 1
An example query of how many books are availeble at given time
Select tblBook.BookId, MAX(tblBook.copies) - SUM(tblIssue.copies) as countOfAvailebleBooks
FROm tblBook
FULL join tblIssue
ON tblBook.BookId = tblIssue.BookId
WHERE tblIssue.ReturnDate >= '2015-10-12'AND tblIssue.IssueDate <= '2015-10-12'
This will produce an aggregate result for a given date, which is 2015-10-12 for this case, of how many books you are availeble, it is not optimal but what you have given, it seems like it is the best solution.

Related

SQL - specific requirement to compare tables

I'm trying to merge 2 queries into 1 (cuts the number of daily queries in half): I have 2 tables, I want to do a query against 1 table, then the same query against the other table that has the same list just less entries.
Basically its a list of (let's call it for obfuscation) people and hobby. One table is ALL people & hobby, the other shorter list is people & hobby that I've met. Table 2 would all be found in table 1. Table 1 includes entries (people I have yet to meet) not found in table 2
The tables are synced up from elsewhere, what I'm looking to do is print a list of ALL people in the first column then print the hobby ONLY of people that are on both lists. That way I can see the lists merged, and track the rate at which the gap between both lists is closing. I have tried a number of SQL combinations but they either filter out the first table and match only items that are true for both (i.e. just giving me table 2) or just adding table 2 to table 1.
Example of what I'm trying to do below:
+---------+----------+--+----------+---------+--+---------+----------+
| table1 | | | table2 | | | query | |
+---------+----------+--+----------+---------+--+---------+----------+
| name | hobby | | activity | person | | name | hobby |
| bob | fishing | | fishing | bob | | bob | fishing |
| bill | vidgames | | hiking | sarah | | bill | |
| sarah | hiking | | planking | sabrina | | sarah | hiking |
| mike | cooking | | | | | mike | |
| sabrina | planking | | | | | sabrina | planking |
+---------+----------+--+----------+---------+--+---------+----------+
Normally I'd just take the few days to learn SQL a bit better however I'm stretched pretty thin at work as it is!
I should mention the table 2 is flipped and the headings are all unique (don't think this matters)!
I think you just want a left join:
select t1.name, t2.activity as hobby
from table1 t1 left join
table2 t2
on t1.name = t2.person;

Returning singular row/value from joined table date based on closest date

I have a Production Table and a Standing Data table. The relationship of Production to Standing Data is actually Many-To-Many which is different to how this relationship is usually represented (Many-to-One).
The standing data table holds a list of tasks and the score each task is worth. Tasks can appear multiple times with different "ValidFrom" dates for changing the score at different points in time. What I am trying to do is query the Production Table so that the TaskID is looked up in the table and uses the date it was logged to check what score it should return.
Here's an example of how I want the data to look:
Production Table:
+----------+------------+-------+-----------+--------+-------+
| RecordID | Date | EmpID | Reference | TaskID | Score |
+----------+------------+-------+-----------+--------+-------+
| 1 | 27/02/2020 | 1 | 123 | 1 | 1.5 |
| 2 | 27/02/2020 | 1 | 123 | 1 | 1.5 |
| 3 | 30/02/2020 | 1 | 123 | 1 | 2 |
| 4 | 31/02/2020 | 1 | 123 | 1 | 2 |
+----------+------------+-------+-----------+--------+-------+
Standing Data
+----------+--------+----------------+-------+
| RecordID | TaskID | DateActiveFrom | Score |
+----------+--------+----------------+-------+
| 1 | 1 | 01/02/2020 | 1.5 |
| 2 | 1 | 28/02/2020 | 2 |
+----------+--------+----------------+-------+
I have tried the below code but unfortunately due to multiple records meeting the criteria, the production data duplicates with two different scores per record:
SELECT p.[RecordID],
p.[Date],
p.[EmpID],
p.[Reference],
p.[TaskID],
s.[Score]
FROM ProductionTable as p
LEFT JOIN StandingDataTable as s
ON s.[TaskID] = p.[TaskID]
AND s.[DateActiveFrom] <= p.[Date];
What is the correct way to return the correct and singular/scalar Score value for this record based on the date?
You can use apply :
SELECT p.[RecordID], p.[Date], p.[EmpID], p.[Reference], p.[TaskID], s.[Score]
FROM ProductionTable as p OUTER APPLY
( SELECT TOP (1) s.[Score]
FROM StandingDataTable AS s
WHERE s.[TaskID] = p.[TaskID] AND
s.[DateActiveFrom] <= p.[Date]
ORDER BY S.DateActiveFrom DESC
) s;
You might want score basis on Record Level if so, change the where clause in apply.

Using a table to lookup multiple IDs on one row

I have two tables I am using at work to help me gain experience in writing SQL queries. One table contains a list of Applications and has three columns -
Application_Name, Application_Contact_ID and Business_Contact_ID. I then have a separate table called Contacts with two columns - Contact_ID and Contact_Name. I am trying to write a query that will list the Application_Name and Contact_Name for both the Applications_Contact_ID and Business_Contact_ID columns instead of the ID number itself.
I understand I need to JOIN the two tables but I haven't quite figured out how to formulate the correct statement. Help Please!
APPLICATIONS TABLE:
+------------------+------------------------+---------------------+
| Application_Name | Application_Contact_ID | Business_Contact_ID |
+------------------+------------------------+---------------------+
| Adobe | 23 | 23 |
| Word | 52 | 14 |
| NotePad++ | 44 | 989 |
+------------------+------------------------+---------------------+
CONTACTS TABLE:
+------------+--------------+
| Contact_ID | Contact_Name |
+------------+--------------+
| 23 | Tim |
| 52 | John |
| 14 | Jen |
| 44 | Carl |
| 989 | Sam |
+------------+--------------+
What I am trying to get is:
+------------------+--------------------------+-----------------------+
| Application_Name | Application_Contact_Name | Business_Contact_Name |
+------------------+--------------------------+-----------------------+
| Adobe | Tim | Tim |
| Word | John | Jen |
| NotePad++ | Carl | Sam |
+------------------+--------------------------+-----------------------+
I've tried the below but it is only returning the name for one of the columns:
SELECT Application_Name, Application_Contact_ID, Business_Contact_ID, Contact_Name
FROM Applications
JOIN Contact ON Contact_ID = Application_Contact_ID
This is a pretty critical and 101 part of SQL. Consider reading this other answer on a different question, which explains the joins in more depth. The trick to your query, is that you have to join the CONTACTS table twice, which is a bit hard to visualize, because you have to go there for both the application_contact_id and business_contact_id.
There are many flavors of joins (INNER, LEFT, RIGHT, etc.), which you'll want to familiarize yourself with for the future reference. Consider reading this article at the very least: https://www.techonthenet.com/sql_server/joins.php.
SELECT t1.application_name Application_Name,
t2.contact_name Application_Contact_name,
t3.contact_name Business_Contact_name
FROM applications t1
INNER JOIN contacts ON t2 t1.Application_Contact_ID = t2.contact_id -- join contacts for appName
INNER JOIN contacts ON t3 t1.business_Contact_ID = t3.contact_id; -- join contacts for busName

Four Table Join in BigQuery

Okay, so I'm trying to link together four different tables, and its getting very difficult. I provided snippets of each table in the hopes you all could help out
Table 1: data
+--------+--------+-----------+
| charge | amount | date |
+--------+--------+-----------+
| 123 | 10000 | 2/10/2016 |
| 456 | 10000 | 1/28/2016 |
| 789 | 10000 | 3/30/2016 |
+--------+--------+-----------+
Table 2: data_metadata
+--------+------------+------------+
| charge | key | value |
+--------+------------+------------+
| 123 | identifier | trrkfll212 |
| 456 | code | test |
| 789 | ID | 123xyz |
+--------+------------+------------+
Table 3: buyer
+-----+-----------+----------+----------+
| id | date | discount | plan |
+-----+-----------+----------+----------+
| ABC | 2/13/2016 | yes | option a |
| DEF | 2/1/2016 | yes | option a |
| GHI | 1/22/2016 | no | option a |
+-----+-----------+----------+----------+
Table 4: buyer_metadata
+--------------+-----------+--------+
| id | |key| | value |
+--------------+-----------+--------+
| ABC | migration | TRUE |
| DEF | emid | foo |
| GHI | ID | 123xyz |
+--------------+-----------+--------+
Okay, so the tables data and data_metadata are obviously connected by the charge column.
The tables buyer and buyer_metadata are connected by the id column.
But I want to link all of them together. I'm pretty sure the way to accomplish this is through linking the metadata tables together through the common field in the "value" column (in this example: 123xyz).
Could anyone help?
This might look like something like that if all "link" columns are unique :
SELECT *
FROM data d
JOIN data_metadata dm ON d.charge = dm.charge
JOIN buyer_metada bm ON dm.value = bm.value
JOIN buyer b ON bm.id = b.id
If not, I think you'll have to use something like GROUP BY clause
Let's take it in two steps, first create composite tables for data and buyer. Composite table for data:
SELECT data.charge, data.amount, data.date,
data_metadata.key, data_metadata.value
FROM [data] AS data
JOIN (SELECT charge, key, value FROM [data_metadata]) AS data_metadata
ON data.charge = data_metadata.charge
And composite table for buyer:
SELECT buyer.id, buyer.date, buyer.discount, buyer.plan,
buyer_metadata.key, buyer_metadata.value
FROM [buyer] AS buyer
JOIN (SELECT key, value FROM [buyer_metadata]) AS buyer_metadata
ON buyer.id = buyer_metadata.id
And then let's join the two composite tables
SELECT composite_data.*, composite_buyer.*
FROM (
SELECT data.charge, data.amount, data.date,
data_metadata.key, data_metadata.value
FROM [data] AS data
JOIN (SELECT charge, key, value FROM [data_metadata]) AS data_metadata
ON data.charge = data_metadata.charge) AS composite_data
JOIN (
SELECT buyer.id, buyer.date, buyer.discount, buyer.plan,
buyer_metadata.key, buyer_metadata.value
FROM [buyer] AS buyer
JOIN (SELECT key, value FROM [buyer_metadata]) AS buyer_metadata
ON buyer.id = buyer_metadata.id) AS composite_buyer
ON composite_data.value = composite_buyer.value
I haven't tested it but it's probably close.
For reference, here is the page on BigQuery JOINs. And have you seen this SO?

SQL deleting rows with duplicate dates conditional upon values in two columns

I have data on approx 1000 individuals, where each individual can have multiple rows, with multiple dates and where the columns indicate the program admitted to and a code number.
I need each row to contain a distinct date, so I need to delete the rows of duplicate dates from my table. Where there are multiple rows with the same date, I need to keep the row that has the lowest code number. In the case of more than one row having both the same date and the same lowest code, then I need to keep the row that also has been in program (prog) B. For example;
| ID | DATE | CODE | PROG|
--------------------------------
| 1 | 1996-08-16 | 24 | A |
| 1 | 1997-06-02 | 123 | A |
| 1 | 1997-06-02 | 123 | B |
| 1 | 1997-06-02 | 211 | B |
| 1 | 1997-08-19 | 67 | A |
| 1 | 1997-08-19 | 23 | A |
So my desired output would look like this;
| ID | DATE | CODE | PROG|
--------------------------------
| 1 | 1996-08-16 | 24 | A |
| 1 | 1997-06-02 | 123 | B |
| 1 | 1997-08-19 | 23 | A |
I'm struggling to come up with a solution to this, so any help greatly appreciated!
Microsoft SQL Server 2012 (X64)
The following works with your test data
SELECT ID, date, MIN(code), MAX(prog) FROM table
GROUP BY date
You can then use the results of this query to create a new table or populate a new table. Or to delete all records not returned by this query.
SQLFiddle http://sqlfiddle.com/#!9/0ebb5/5
You can use min() function: (See the details here)
select ID, DATE, min(CODE), max(PROG)
from table
group by DATE
I assume that your table has a valid primary key. However i would recommend you to take IDas Primary key. Hope this would help you.