I have a requirement to join three tables which have the same structure as shown below.
I need to join these tables based on the store and date field values as shown below:
The complex part here is that even if the row in a table does not match with the other tables, it should create a new row with the other values as zero. For example if there is no shipped and allocated quantities for a store on a particular day but if there is a canceled quantity on that day, a new row should be created with shipped $ allocated values set to 0 and cancelled field value set to the correct value. Can anybody suggest the best method to approach this?
this should work
select alldates.procdate,
alldates.store,
st.quantity as ship_quantity,
ct.quantity as cancel_quantity,
at.quantity as allocation_quantity
from (select procdate, store from shp_table union
select procdate, store from cnl_table union
select procdate, store from aloc_table) alldates
left join shp_table st on alldates.procdate = st.procdate and alldates.store = st.store
left join cnl_table ct on alldates.procdate = ct.procdate and alldates.store = ct.store
left join aloc_table at on alldates.procdate = at.procdate and alldates.store = at.store
Related
I have a weird question - I understand that Joins return matching data based on the 'ON' stipulation, however the problem I am facing is I need the Business date back for both tables but at the same time i need to join on the date in order to get the totals correct
See below code:
Select
o.Resort,
o.Business_Date,
Occupied,
Comps,
House,
ADR,
Room_Revenue,
Occupied-(Comps+House) AS DandT,
Coalesce(gd.Projected_Occ1,0) AS Projected_Occ1,
Occupied-(Comps+House)+Coalesce(gd.Projected_Occ1,0) as Total
from Occupancy o
left join Group_Details_HF gd
on o.Business_Date = gd.Business_Date
and o.Resort = gd.resort
UNION ALL
select
o.Resort,
o.Business_Date,
Occupied,
Comps,
House,
ADR,
Room_Revenue,
Occupied-(Comps+House) AS DandT,
Coalesce(gd.Projected_Occ1,0) AS Projected_Occ1,
Coalesce(Occupied-(Comps+House),0)+Coalesce(gd.Projected_Occ1,0) as Total
from Occupancy_Forecast o
FULL OUTER JOIN Group_Details_HF gd
on o.Business_Date = gd.Business_Date
and o.Resort = gd.resort
Currently, this gives me the desired results from the Occupancy and Occupancy forecast table however when the business date does not exist in the occupancy forecast table it ignores the group_details table, I need the results to combine the dates when they exist in both or give the unique results for each when there is no match
I have decided to create another pivot table storing the details from Group_Details_HF and then Union together the two tables which has given me the desired result rather than fiddling with the join :)
I have a table which contains all the active loans for every month (for example 2017_01, 2017_02, 2017_03, etc). As I don't have another table which contains the Non Active loans (the closed ones) I have to manipulate the same table to get the closed loans for every specific months.
I have tried RIGHT OUTER JOIN in order to get the loans which are part of the previous YEAR_MONTH and have a NULL value in the next month, but as the table is joining itself using the LOAN_NUMBER field as a key, I am not getting the desired results.
Any idea of what I can do?
Ps: In other cases I needed to do that I used the "WHERE NOT EXISTS" clause, but I had two different tables.
My query is:
SELECT DM07MD.LOAN_NUMBER, DM07MD2.LOAN_NUMBER AS L2
FROM [dbo].[DM_07MONTHLY_DATA] DM07MD
LEFT OUTER JOIN [dbo].[DM_07MONTHLY_DATA] DM07MD2
ON DM07MD.LOAN_NUMBER = DM07MD2.LOAN_NUMBER
AND DM07MD.YYYY_MM = '2017_01'
WHERE DM07MD.S90T01_CLIENT_SEGMENT IN ('PI', 'MICRO')
AND DM07MD.S90T01_IS_RESTRUCTURED = 1
AND DM07MD2.LOAN_NUMBER IS NULL
AND DM07MD.YYYY_MM = '2017_02'
You can get the same by using exists,
SELECT DM07MD.LOAN_NUMBER FROM [dbo].[DM_07MONTHLY_DATA] DM07MD where DM07MD.YYYY_MM = '2017_02' and not exists
( SELECT 1 FROM [dbo].[DM_07MONTHLY_DATA] DM07MD2 where DM07MD.YYYY_MM = '2017_01' and DM07MD.LOAN_NUMBER=DM07MD2.LOAN_NUMBER )
How to print all readers, where time between last two borrows is more than 2 months?
select
name, surname, max(k1.borrow_date)
from
k_person
join
k_reader using(person_id)
join
k_rent_books k1 using(reader_id)
join
k_rent_books k2 using(reader_id)
where
months_between(add_months((k1.borrow_date),-2),k2.borrow_date) > 2
group by
name, surname, person_id
order by
surname;
But i dont know how to say that compare two last dates.
Thanks for help.
Due to some restrictions with the USING clause (e.g. ORA-25154), I had to switch the join syntax, but here's one option. Basically the way to find the last and second last borrow dates for a reader is as follows:
Join to one copy of the K_RENT_BOOKS (K_RB1) table and finds the row with the latest BORROW_DATE for the current reader (from K_READER).
Next, it joins to a second copy of K_RENT_BOOKS (K_RB2), again for
the current reader and finds the latest BORROW_DATE that is not the
one found in the first copy (K_FB1).
Keep the resulting joined record if the last borrow date is two
months after the 2nd last borrow date.
--
select k_p.name, k_rb1.borrow_date, k_rb2.borrow_date
from k_person k_p
inner join
k_reader k_r
on k_p.person_id = k_r.person_id
inner join
k_rent_books k_rb1
on k_rb1.reader_id = k_r.reader_id
inner join
k_rent_books k_rb2
on k_rb2.reader_id = k_r.reader_id
where k_rb1.borrow_date = (select max(borrow_date)
from k_rent_books k_rb3
where k_rb3.reader_id = k_r.reader_id
)
and k_rb2.borrow_date = (select max(borrow_date)
from k_rent_books k_rb4
where k_rb4.reader_id = k_r.reader_id
and k_rb4.borrow_date <> k_rb1.borrow_date
)
and months_between(k_rb1.borrow_date, k_rb2.borrow_date) > 2
There are other ways of doing this that may be faster (e.g. using a with clause that generates the last and second last borrow dates for all readers) but hopefully this provides a starting point.
I have three tables that need to be joined in order to get monthly inventory data in return.
Table 1: TargetInventory
Table 2: TargetValue
Table 3: TargetWeight
[TargetInventory] does not change after being added the first time.
[TargetValue] is just a small table that includes prices of various types of metal.
[TargetWeight] is updated monthly as part of our inventory process. We INSERT new data, we never UPDATE old data.
Below is the relationship between these tables. (Sorry, I don't have the reputation points to post an image. Brand new here, so hopefully this makes sense.)
(* = UniqueKey)
--TargetValue-- --TargetInventory-- --TargetWeight--
*MaterialID <===| *TargetID <=====| *ID
Material |===> MaterialID |===> TargetID
PricePerOunce Length RecordDate
Density Width Weight
Thickness
DateInInventory
The TargetWeight table contains multiple records for TargetID (since a new one is added every month at inventory). That's good for me to track historical usage, but for the current inventory value, I only need the most recent TargetWeight.Weight to be returned.
I don't know how to do a CROSS APPLY from within another INNER JOIN, so I'm at a loss for how to do this (without switching to mySQL and just doing a LIMIT 1...)
I think it needs to look something like what's below, but I'm not sure how to finish the query.
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
TargetWeight.ID,
TargetWeight.TargetID AS TargetWeight_TargetID,
TargetWeight.RecordDate,
TargetWeight.Weight
FROM
(TargetValue
INNER JOIN TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
CROSS APPLY (
SELECT TOP 1 *
FROM .....
)
The following query works for me in Access 2010. It uses an INNER JOIN on a subquery to take the place of the CROSS APPLY (which Access SQL doesn't support). It assumes that there will be no more than one [TargetWeight] record for a given (TargetID, RecordDate):
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
LatestWeight.ID,
LatestWeight.TargetID AS TargetWeight_TargetID,
LatestWeight.RecordDate,
LatestWeight.Weight
FROM
(
TargetValue
INNER JOIN
TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
INNER JOIN
(
SELECT tw.*
FROM
TargetWeight AS tw
INNER JOIN
(
SELECT TargetID, MAX(RecordDate) AS LatestDate
FROM TargetWeight
GROUP BY TargetID
) AS latest
ON latest.TargetID=tw.TargetID
AND latest.LatestDate=tw.RecordDate
) AS LatestWeight
ON LatestWeight.TargetID = TargetInventory.TargetID
Alternative approach specifically for Access 2010 or later
If the above query bogs down with a large number of rows in [TargetWeight] then another possible solution for Access 2010+ would be to add a Yes/No field named [Current] to the [TargetWeight] table and use the following After Insert data macro to ensure that only the latest record for each [TargetID] is flagged as [Current]:
Once that is done, the query would simply be
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
TargetWeight.ID,
TargetWeight.TargetID AS TargetWeight_TargetID,
TargetWeight.RecordDate,
TargetWeight.Weight
FROM
(
TargetValue
INNER JOIN
TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
INNER JOIN
TargetWeight
ON TargetInventory.TargetID = TargetWeight.TargetID
WHERE TargetWeight.Current = True;
To maximize performance, the [TargetWeight].[TargetID] and [TargetWeight].[Current] fields should be indexed.
SELECT TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density, Weight.ID,
Weight.TargetID AS TargetWeight_TargetID,
Weight.RecordDate,
Weight.Weight
FROM TargetInventory
INNER JOIN TargetValue ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
CROSS APPLY (
SELECT TOP 1 *
FROM TargetWeight
WHERE TargetID = TargetInventory.TargetID
ORDER BY RecordDate DESC
) AS Weight
Need help on a query using sql server 2005
I am having two tables
code
chargecode
chargeid
orgid
entry
chargeid
itemNo
rate
I need to list all the chargeids in entry table if it contains multiple entries having different chargeids
which got listed in code table having the same charge code.
data :
code
100,1,100
100,2,100
100,3,100
101,11,100
101,12,100
entry
1,x1,1
1,x2,2
2,x3,2
11,x4,1
11,x5,1
using the above data , it query should list chargeids 1 and 2 and not 11.
I got the way to know how many rows in entry satisfies the criteria, but m failing to get the chargeids
select count (distinct chargeId)
from entry where chargeid in (select chargeid from code where chargecode = (SELECT A.chargecode
from code as A join code as B
ON A.chargecode = B.chargeCode and A.chargetype = B.chargetype and A.orgId = B.orgId AND A.CHARGEID = b.CHARGEid
group by A.chargecode,A.orgid
having count(A.chargecode) > 1)
)
First off: I apologise for my completely inaccurate original answer.
The solution to your problem is a self-join. Self-joins are used when you want to select more than one row from the same table. In our case we want to select two charge IDs that have the same charge code:
SELECT DISTINCT c1.chargeid, c2.chargeid FROM code c1
JOIN code c2 ON c1.chargeid != c2.chargeid AND c1.chargecode = c2.chargecode
JOIN entry e1 ON e1.chargeid = c1.chargeid
JOIN entry e2 ON e2.chargeid = c2.chargeid
WHERE c1.chargeid < c2.chargeid
Explanation of this:
First we pick any two charge IDs from 'code'. The DISTINCT avoids duplicates. We make sure they're two different IDs and that they map to the same chargecode.
Then we join on 'entry' (twice) to make sure they both appear in the entry table.
This approach gives (for your example) the pairs (1,2) and (2,1). So we also insist on an ordering; this cuts to result set down to just (1,2), as you described.