Pull column value from second to last row - sql

I'm stuck in a loop of figuring out a game plan for this in SQL. Below is my sample data. I'm trying to create another column called "Starting Balance" which would be the amount in "Ending Balance" for the previous LINE. When I have that, I would only like to display where reason = count and forget about the rest.
I can't even fathom what approach to take and any advice would be appreciated.
Sample Data:
ITEM ID
ITEM
LAST UPDATED
REASON
ENDING BALANCE
LINE
123
Pencil
9/1/2020
Correction
400
1
123
Pencil
9/2/2020
Correction
450
2
123
Pencil
9/3/2020
Count
500
3
Expected Output:
ITEM ID
ITEM
LAST UPDATED
REASON
Starting Balance
ENDING BALANCE
123
Pencil
9/3/2020
Count
450
500

if "previous LINE" means the row with Lastupdated before current row:
select * from (
select * , lag(ENDING_BALANCE,1,0) over (partition by ItemId order by LASTUPDATED) as Starting Balance
from table
) t where t.REASON = 'count'

I can't bugtest this, but maybe something like:
SELECT
a.ITEM_ID,
a.ITEM,
a.LAST_UPDATED,
"Count" AS REASON,
b.ENDING_BALANCE AS Starting_Balance,
a.ENDING_BALANCE AS ENDING_BALANCE,
FROM table a
LEFT JOIN table b
ON a.ITEM_ID = b.ITEM_ID, a.LINE = b.LINE + 1
Note that we're joining two copies of the same table together here and labeling them a and b.
No clue if you can do ONs like that, but you could also make the join table have a LINE +1 column which you then use to join.

Related

how to turn a wide table into a long table

I have a wide table that looks like this:
Case REFERENCE
OUTCOME_EMP_SITUATION
MONTH1_EMP_SITUATION
MONTH1_REASON
MONTH3_EMP_SITUATION
MONTH3_REASON
MONTH6_EMP_SITUATION
MONTH6_REASON
12345
Employed
Employed
Outcome at 1 month
Employed
Outcome at 3 month
Employed
Outcome at 6 month
this is survey results that people completed after they finished employment program. They complete the survey 4 times, once immediately after finishing the program, and then after 1/3/6 month. the problem is, the results for immediately after program completion are in one table (Outcome table) and the 1/3/6 month checkpoint results are in another table (Checkpointinfo table) I would like to combine those tables to create a long table so that instead of having "Outcome" in 5 different columns, I would have it in one column and it would look like this:
Case Reference
Outcome_emp_situation
Month_Reason
12345
Employed
NULL
12345
Employed
Outcome at 1 month
12345
Employed
Outcome at 3 month
12345
Employed
Outcome at 6 month
I was wondering if anyone could please help me out to turn this wide query into a long table query.
Here is the query for the wide table:
Select
ch.CASEREFERENCE, oc.OUTCOME_DATE, oc.OUTCOME_REFERENCE_ID, oc.OUTCOME_EMP_SITUATION, oc.OUTCOME_EMPLOYMENT_TYPE, oc.OUTCOME_NUM_JOBS, oc.OUTCOME_NAICS_DESC, oc.OUTCOME_JOB_NATURE,
oc.OUTCOME_WORK_HOURS, oc.OUTCOME_WAGE, oc.OUTCOME_STUDENT_STATUS, oc.OUTCOME_GOT_SERVICE, oc.OUTCOME_RIGHT_SERVICE, oc.OUTCOME_RECOMMEND_PROGRAM,
ck1.REASONCODE AS REASONCODE1,
CASE WHEN ck1.REASONCODE = 'OT1' THEN "Outcome at 1 month" END MONTH1_REASON,
ck1.MONTH_START_DATE AS MONTH1_START_DATE, ck1.MONTH_END_DATE AS MONTH1_END_DATE, ck1.MONTH_OUTCOME_EMP_SITUATION AS MONTH1_OUTCOME_EMP_SITUATION,
ck1.MONTH_EMPLOYMENT_TYPE AS MONTH1_EMPLOYMENT_TYPE, ck1.MONTH_NUM_JOBS AS ,MONTH1_NUM_JOBS, ck1.MONTH_NAICS_DESC AS MONTH1_NAICS_DESC, ck1.MONTH_JOB_NATURE AS MONTH1_JOB_NATURE,
ck1.MONTH_WORK_HOURS AS MONTH1_WORK_HOURS, ck1.MONTH_WAGE AS MONTH1_WAGE, ck1.MONTH_STUDENT_STATUS AS MONTH1_STUDENT_STATUS, ck1.MONTH_GOT_SERVICE AS MONTH1_GOT_SERVICE,
ck1.MONTH_RIGHT_SERVICE AS MONTH1_RIGHT_SERVICE, ck1.MONTH_RECOMMEND_PROGRAM AS MONTH1_RECOMMEND_PROGRAM, ck1.MONTH_RESUBMIT_MILESTONE AS MONTH1_RESUBMIT_MILESTONE,
ck1.MONTH_MILESTONE_ACHIEVED AS MONTH1_MILESTONE_ACHIEVED, ck1.MONTH_APPROVED_DATE AS MONTH1_APPROVED_DATE,
ck3.REASONCODE AS REASONCODE3,
CASE WHEN ck3.REASONCODE = 'OT3' THEN "Outcome at 3 month" END MONTH3_REASON,
ck3.MONTH_START_DATE AS MONTH3_START_DATE, ck3.MONTH_END_DATE AS MONTH3_END_DATE, ck3.MONTH_OUTCOME_EMP_SITUATION AS MONTH3_OUTCOME_EMP_SITUATION,
ck3.MONTH_EMPLOYMENT_TYPE AS MONTH3_EMPLOYMENT_TYPE, ck3.MONTH_NUM_JOBS AS ,MONTH3_NUM_JOBS, ck3.MONTH_NAICS_DESC AS MONTH3_NAICS_DESC, ck3.MONTH_JOB_NATURE AS MONTH3_JOB_NATURE,
ck3.MONTH_WORK_HOURS AS MONTH3_WORK_HOURS, ck3.MONTH_WAGE AS MONTH3_WAGE, ck3.MONTH_STUDENT_STATUS AS MONTH3_STUDENT_STATUS, ck3.MONTH_GOT_SERVICE AS MONTH3_GOT_SERVICE,
ck3.MONTH_RIGHT_SERVICE AS MONTH3_RIGHT_SERVICE, ck3.MONTH_RECOMMEND_PROGRAM AS MONTH3_RECOMMEND_PROGRAM, ck3.MONTH_RESUBMIT_MILESTONE AS MONTH3_RESUBMIT_MILESTONE,
ck3.MONTH_MILESTONE_ACHIEVED AS MONTH3_MILESTONE_ACHIEVED, ck3.MONTH_APPROVED_DATE AS MONTH3_APPROVED_DATE,
ck6.REASONCODE AS REASONCODE6,
CASE WHEN ck6.REASONCODE = 'OT6' THEN "Outcome at 6 month" END MONTH6_REASON,
ck6.MONTH_START_DATE AS MONTH6_START_DATE, ck6.MONTH_END_DATE AS MONTH6_END_DATE, ck6.MONTH_OUTCOME_EMP_SITUATION AS MONTH6_OUTCOME_EMP_SITUATION,
ck6.MONTH_EMPLOYMENT_TYPE AS MONTH6_EMPLOYMENT_TYPE, ck6.MONTH_NUM_JOBS AS ,MONTH6_NUM_JOBS, ck6.MONTH_NAICS_DESC AS MONTH6_NAICS_DESC, ck6.MONTH_JOB_NATURE AS MONTH6_JOB_NATURE,
ck6.MONTH_WORK_HOURS AS MONTH6_WORK_HOURS, ck6.MONTH_WAGE AS MONTH6_WAGE, ck6.MONTH_STUDENT_STATUS AS MONTH6_STUDENT_STATUS, ck6.MONTH_GOT_SERVICE AS MONTH6_GOT_SERVICE,
ck6.MONTH_RIGHT_SERVICE AS MONTH6_RIGHT_SERVICE, ck6.MONTH_RECOMMEND_PROGRAM AS MONTH6_RECOMMEND_PROGRAM, ck6.MONTH_RESUBMIT_MILESTONE AS MONTH6_RESUBMIT_MILESTONE,
ck6.MONTH_MILESTONE_ACHIEVED AS MONTH6_MILESTONE_ACHIEVED, ck6.MONTH_APPROVED_DATE AS MONTH6_APPROVED_DATE
FROM PROGRAM as pg
LEFT JOIN CASEINFO as ch ON pg.CASEID = ch.CASEID
LEFT JOIN OUTCOME as oc ON pg.CASEID = oc.CASEID
LEFT JOIN ( SELECT cp.CASEID, cp.REASONCODE, cp.MONTH_OUTCOME_EMP_SITUATION, cpi.* FROM CHECKPOINT cp LEFT JOIN CHECKPOINTINFO cpi ON cp.CASEREVIEWID = cpi.CASEREVIEWID WHERE cpi.REASONCODE = 'OT1')ck1 ON pg.CASEID = ck1.CASEID
LEFT JOIN ( SELECT cp.CASEID, cp.REASONCODE, cp.MONTH_OUTCOME_EMP_SITUATION, cpi.* FROM CHECKPOINT cp LEFT JOIN CHECKPOINTINFO cpi ON cp.CASEREVIEWID = cpi.CASEREVIEWID WHERE cpi.REASONCODE = 'OT3')ck3 ON pg.CASEID = ck3.CASEID
LEFT JOIN ( SELECT cp.CASEID, cp.REASONCODE, cp.MONTH_OUTCOME_EMP_SITUATION, cpi.* FROM CHECKPOINT cp LEFT JOIN CHECKPOINTINFO cpi ON cp.CASEREVIEWID = cpi.CASEREVIEWID WHERE cpi.REASONCODE = 'OT6')ck6 ON pg.CASEID = ck6.CASEID
If someone could please help me turn this wide table into a long table, it would be much appreciated.
thank you
You need to do unpivot for outcome and reason columns. But first you need an extra column for overall reason. This is the query:
with a as (
select 12345 as case_reference,
'Employed' as OUTCOME_EMP_SITUATION,
'Employed' as MONTH1_EMP_SITUATION,
'Outcome at 1 month' as MONTH1_REASON,
'Employed' as MONTH3_EMP_SITUATION,
'Outcome at 3 month' as MONTH3_REASON,
'Employed' as MONTH6_EMP_SITUATION,
'Outcome at 6 month' as MONTH6_REASON
from dual
)
select
case_reference,
outcome_emp_situation,
month_reason
from (
select a.*,
cast(null as varchar2(1000)) as reason
from a
) a
unpivot(
(Outcome_emp_situation, Month_Reason)
for mon in (
(OUTCOME_EMP_SITUATION, reason) as 0,
(MONTH1_EMP_SITUATION, MONTH1_REASON) as 1,
(MONTH3_EMP_SITUATION, MONTH3_REASON) as 3,
(MONTH6_EMP_SITUATION, MONTH6_REASON) as 6
)
)
order by mon asc
CASE_REFERENCE | OUTCOME_EMP_SITUATION | MONTH_REASON
-------------: | :-------------------- | :-----------------
12345 | Employed | null
12345 | Employed | Outcome at 1 month
12345 | Employed | Outcome at 3 month
12345 | Employed | Outcome at 6 month
db<>fiddle here
UPD: The explanation below.
The tuple just after unpivot keyword is the result column names, column after for keyword identifies column group which produced that values. Tuples inside in define the columns' groups: for each group that columns' values will be passed to the corresponding (by position) columns of the result tuple and new row will be generated with the value of for column defined after as keyword.
So if you need more columns to be transferred to each row, you need to add new columns to the result tuple (after unpivot) and to each column group inside in. If for some reason you have not enough columns to pass for some groups, you can wrap your source query with outer select and add dummy (or constantly valued) columns for that groups.
Note:
Datatypes of each tuples should be the same (or convertible according to default datatype precedence). I.e. each tuple's member on the same position should have the same type, members at different positions may have different types.
You can reuse the same column in multiple groups and positions.

How do I stop my query from pulling duplicates?

Yes, I know this seems simple:
SELECT DISTINCT(...)
Except, it apparently isn't
Here is my actual Query:
SELECT
DeclinationReasons.Reason,
EmployeeInformation.ID,
EmployeeInformation.Employee,
EmployeeInformation.Active,
CompletedTrainings.DecShotDate,
CompletedTrainings.DecShotLocation,
CompletedTrainings.DecReason,
CompletedTrainings.DecExplanation,
IIf([DecShotLocation]="MCS","Yes","No") AS YesMCS,
IIf([DecReason]=1,1,0) AS YesAllergy,
IIf([DecReason]=2,1,0) AS YesImmune,
IIf([DecReason]=3,1,0) AS YesAdverse,
IIf([DecReason]=4,1,0) AS YesMedical,
IIf([DecReason]=5,1,0) AS YesSpiritual,
IIf([DecReason]=6,1,0) AS YesOther,
IIf([DecReason]=7,1,0) AS YesAlready
FROM
EmployeeInformation
INNER JOIN (CompletedTrainings
LEFT JOIN DeclinationReasons ON CompletedTrainings.DecReason = DeclinationReasons.ReasonID)
ON EmployeeInformation.ID = CompletedTrainings.Employee
GROUP BY
DeclinationReasons.Reason,
EmployeeInformation.ID,
EmployeeInformation.Employee,
EmployeeInformation.Active,
CompletedTrainings.DecShotDate,
CompletedTrainings.DecShotLocation,
CompletedTrainings.DecReason,
CompletedTrainings.DecExplanation,
IIf([DecShotLocation]="MCS","Yes","No"),
IIf([DecReason]=1,1,0),
IIf([DecReason]=2,1,0),
IIf([DecReason]=3,1,0),
IIf([DecReason]=4,1,0),
IIf([DecReason]=5,1,0),
IIf([DecReason]=6,1,0),
IIf([DecReason]=7,1,0)
HAVING
((((EmployeeInformation.Active) Like -1)
AND ((CompletedTrainings.DecShotDate + 365 >= DATE())
OR (CompletedTrainings.DecShotDate IS NULL))));
This is Joining a few tables (obviously) in order to get a number of records. The problem is that if someone is duplicated on the table with a NULL in one of the date fields, and a date in another field, it pulls both the NULL and the DATE, or pulls multiple NULLS it might pull multiple dates but those are not present right at the moment.
I need the Nulls, they are actual data in this particular case, but if someone has a date and a NULL I need to pull only the newest record, I thought I could add MAX(RecordID) from the table, but that didn't change the results of the query either.
That code:
SELECT
DeclinationReasons.Reason,
EmployeeInformation.ID,
EmployeeInformation.Employee,
EmployeeInformation.Active,
MAX(CompletedTrainings.RecordID),
CompletedTrainings.DecShotDate
...
And it returned the same issue, Duplicated EmployeeInformation.ID with different DecShotDate values.
Currently it returns:
ID
Active
DecShotDate
etc. x a bunch
1
-1
date date
whatever goes
2
-1
in these
2
-1
date date
columns
These are being used in a report, that is to determine the total number of employees who fit the criteria of the report. The NULLs in DecShotDate are needed as they show people who did not refuse to get a flu vaccine in the current year, while the dates are people who did refuse.
Now I have come up with one simple solution, I could add a column to the CompletedTrainings Table that contains a date or other value, and add that to the HAVING statement. This might be the right solution as this is a yearly training questionnaire that employees have to fill out. But I am asking for advice before doing this.
Am I right in thinking I need to add a column to filter by so that older data isn't being pulled, or should I be able to do this by pulling recordID, and did I just bork that part of the query up?
Edited to add raw table views:
EmployeeInformation Table:
ID
Last
First
empID
Active
Termdate
DoH
Title
PT/FT/PD
PI
1
Doe
Jane
982
-1
date
Sr
PD
X
2
Roe
John
278
0
date
date
Jr
PD
X
3
Moe
Larry
1232
-1
date
Sr
FT
X
4
Zoe
Debbie
1424
-1
date
Sr
PT
X
DeclinationReasons Table:
ReasonID
Reason
1
Allergy
2
Already got it
3
Illness
CompletedTrainings Table:
RecordID
Employee
Training
...
DecShotdate
DecShotLocation
DecShotReason
DecExp
1
1
4
date
location
2
text
2
1
4
3
2
4
4
3
4
date
location
3
text
5
3
4
date
location
1
text
6
4
4
After some serious soul searching, I decided to use another column and filter by that.
In the end my query looks like this:
SELECT *
FROM (
(
SELECT RecordID, DecShotDate, DecShotLocation, DecReason, DecExplanation, Employee,
IIf([DecShotLocation]="MCS","Yes","No") AS YesMCS, IIf([DecReason]=1,1,0) AS YesAllergy,
IIf([DecReason]=2,1,0) AS YesImmune, IIf([DecReason]=3,1,0) AS YesAdverse,
IIf([DecReason]=4,1,0) AS YesMedical, IIf([DecReason]=5,1,0) AS YesSpiritual,
IIf([DecReason]=6,1,0) AS YesOther, IIf([DecReason]=7,1,0) AS YesAlready
FROM CompletedTrainings WHERE (CompletedDate > DATE() - 365 ) AND (Training = 69)) AS T1
LEFT JOIN
(
SELECT ID, Active FROM EmployeeInformation) AS T2 ON T1.Employee = T2.ID)
LEFT JOIN
(
SELECT Reason, ReasonID FROM DeclinationReasons) AS T3 ON T1.DecReason = T3.ReasonID;
This may not have been the best solution, but it did exactly what I needed. Which is to get the information by latest entry into the database.
Previously I had tried to use MAX(), DISTINCT(), etc. but always had a problem of multiple records being retrieved. In this case, I intentionally SELECT the most recent records first, then join them to the results of the next query, and so on. Until I have all the required data for my report.
I write this in hopes someone else finds it useful. Or even better if someone tells me why this is wrong, so as to improve my own skills.

SQL statement, check if other rows have the same value

I have a SQL statement that imports my product inventory from a Access.MDB file. The select statement is below. (well a portion of it)
SELECT
Brand, DESCRIPTION AS Model,
SECONDDESCRIPTION AS Description,
PRODUCT AS [Product Code], TYPE AS Batch, INACTIVE,
CORE AS [Core Range],
IIF([CUSTORD] IS NULL, ROUND(ON_HAND), (IIF(TYPE = 'DISP',ROUND(ON_HAND),ROUND(ON_HAND)-CUSTORD))) AS SOH
You may notice that the select statement will minus any items that are on a customer order from the SOH values. for clarity below is the line that does just that.
IIF([CUSTORD] IS NULL, ROUND(ON_HAND), (IIF(TYPE = 'DISP',ROUND(ON_HAND),ROUND(ON_HAND)-CUSTORD))) AS SOH
The problem i have is, that 1 product code, can have multiple batches, and if an item only has a qty of 1 in each batch, and then the customer order column also contains a 1, this results in 1 - 1 = 0.
However the customer orders column is really indicating that only 1 of the product codes in on a customer order, not that specific batch.
Is there a way to check if that product code has already been "Selected" and has a Customer Order Qty against it and if it does then ignore the customer order qty against this next batch in the table?
To help explain it a little here is a rough idea of the table that would be imported.
Product
Batch_Number
ON_HAND
CUSTORD
Apples
123456
5
1
Apples
234567
1
1
Apples
587554
1
1
Bananas
1548777
1
0
so in the table above with my existing select statement, my results would be
Apples 4 in batch 123456
Bananas 1 in batch 1548777
As the next two lines of apples would actually end up with a value of 0 in batches 234567 and 587554
my program is set to then only return to the user values of items they can sell with a SOH qty > 0
so i need the final datatable in my program to look like this:
Product
Batch_Number
ON_HAND
CUSTORD
Apples
123456
5
1
Apples
234567
1
0
Apples
587554
1
0
Bananas
1548777
1
0
In my table Batch Number is the unique identifier and does not occur twice in the table.
Im working in VB.NET so if it could not be done in the SQL select statement i could be open to the idea of adjusting the values in the dataset datatable, however that would probably be made harder by the fact that the SQL Select statement i'm using never actually imports the CUSTORD column of data into my datatable. As i was trying to handle the SOH values directly at the select statement level.
Hope i have not confused anyone, and explained it as simple as possible.
I have no idea what your initial code has to do with the question. But let me assume that you have a table in the format shown in the question and you want to set on_hand to 0 for all but the first row for each product. You can use:
select product, batch_number, custord,
iif( t.batch_number = (select top 1 t2.batch_number
from t as t2
where t2.product = t.product
order by t2.on_hand desc, t2.batch_number
),
t.on_hand, 0
) as adjusted_on_hand
from t
order by product, on_hand desc, batch_number

Combine data from two SQL tables to create new entry in another table

I have three SQL tables as below, the first one named 'repairparts':
repairparts
-----------------------------------
ID Part Quantity
1 AAA1000 1
2 AAB1000 1
3 AAC1000 1
And the second named 'partslist':
partslist
------------------------------------
Part Price
AAA1000 1.50
AAB1000 3.00
AAC1000 2.00
Now with only being given the ID value of '1', I want to be able to take the part number, and quantity from the first table named 'repairparts' linked to that ID, and combine that with the price of the same part number in the second table named 'partslist', and insert those four piece of data in to the third table named 'estimateparts'.
So the outcome would be this being inserted into the table named 'estimateparts':
estimateparts
-----------------------------------
ID Part Quantity Price
1 AAA1000 1 1.50
I've read that I should use the UNION function and have tried the following, but it does nothing:
INSERT INTO estimateparts (ID, Part, Quantity, Price)
SELECT ID, Part, Quantity FROM repairparts WHERE ID='1'
UNION SELECT Price FROM partslist WHERE Part=repairparts.Part
Really appreciate any advice that can be given.
Thank you.
It sounds like you want a simple join, if I'm not missing something:
select rp.id, rp.part, rp.quantity, pl.price
from repairparts rp join
partslist pl
on rp.part = pl.part
where rp.id = 1;

How do you retrieve the top two records within each grouping

In my table, I have data that looks like this:
CODE DATE PRICE
100 1/1/13 $500
100 2/1/13 $521
100 3/3/13 $530
100 5/9/13 $542
222 3/3/13 $20
350 1/1/13 $200
350 3/1/13 $225
Is it possible to create query to pull out the TWO most recent records by DATE? AND only if there are 2+ dates for a specific code. So the result would be:
CODE DATE PRICE
100 5/9/13 $542
100 3/3/13 $530
350 3/1/13 $225
350 1/1/13 $200
Bonus points if you can put both prices/dates on the same line, like this:
CODE OLD_DATE OLD_PRICE NEW_DATE NEW_PRICE
100 3/3/13 $530 5/9/13 $542
350 1/1/13 $200 3/1/13 $225
Thank you!!!
I managed to solve it with 5 sub-queries and 1 rollup query.
First we have a subquery that gives us the MAX date for each code.
Next, we do the same subquery, except we exclude our previous results.
We assume that your data is already rolled up and you won't have duplicate dates for the same code.
Next we bring in the appropriate Code / Price for the latest and 2nd latest date. If a code doesn't exist in the 2nd Max query - then we don't include it at all.
In the union query we're combining the results of both. In the Rollup Query, we're sorting and removing null values generated in the union.
Results:
CODE MaxOfOLDDATE MaxOfOLDPRICE MaxOfNEWDATE MaxOfNEWPRICE
100 2013-03-03 $530.00 2013-05-09 542
350 2013-01-01 $200.00 2013-03-01 225
Using your Data in a table called "Table", create the following queries:
SUB_2ndMaxDatesPerCode:
SELECT Table.CODE, Max(Table.Date) AS MaxOfDATE1
FROM SUB_MaxDatesPerCode RIGHT JOIN [Table] ON (SUB_MaxDatesPerCode.MaxOfDATE = Table.DATE) AND (SUB_MaxDatesPerCode.CODE = Table.CODE)
GROUP BY Table.CODE, SUB_MaxDatesPerCode.CODE
HAVING (((SUB_MaxDatesPerCode.CODE) Is Null));
SUB_MaxDatesPerCode:
SELECT Table.CODE, Max(Table.Date) AS MaxOfDATE
FROM [Table]
GROUP BY Table.CODE;
SUB_2ndMaxData:
SELECT Table.CODE, Table.Date, Table.PRICE
FROM [Table] INNER JOIN SUB_2ndMaxDatesPerCode ON (Table.DATE = SUB_2ndMaxDatesPerCode.MaxOfDATE1) AND (Table.CODE = SUB_2ndMaxDatesPerCode.Table.CODE);
SUB_MaxData:
SELECT Table.CODE, Table.Date, Table.PRICE
FROM ([Table] INNER JOIN SUB_MaxDatesPerCode ON (Table.DATE = SUB_MaxDatesPerCode.MaxOfDATE) AND (Table.CODE = SUB_MaxDatesPerCode.CODE)) INNER JOIN SUB_2ndMaxDatesPerCode ON Table.CODE = SUB_2ndMaxDatesPerCode.Table.CODE;
SUB_Data:
SELECT CODE, DATE AS OLDDATE, PRICE AS OLDPRICE, NULL AS NEWDATE, NULL AS NEWPRICE FROM SUB_2ndMaxData;
UNION ALL SELECT CODE, NULL AS OLDDATE, NULL AS OLDPRICE, DATE AS NEWDATE, PRICE AS NEWPRICE FROM SUB_MaxData;
Data (Rollup):
SELECT SUB_Data.CODE, Max(SUB_Data.OLDDATE) AS MaxOfOLDDATE, Max(SUB_Data.OLDPRICE) AS MaxOfOLDPRICE, Max(SUB_Data.NEWDATE) AS MaxOfNEWDATE, Max(SUB_Data.NEWPRICE) AS MaxOfNEWPRICE
FROM SUB_Data
GROUP BY SUB_Data.CODE
ORDER BY SUB_Data.CODE;
There you go - thanks for the challenge.
Accessing the recent data
To access the recent data, you use TOP 2. Such as you inverse the data from the table, then select the top 2. Just as you start ABC from ZYX and select the TOP 2 which would provide you with ZY.
SELECT TOP 2 * FROM table_name ORDER BY column_time DESC;
This way, you reverse the table, and then select the most recent two from the top.
Joining the Tables
To join the two columns and create a result from there quest you can use JOIN (INNER JOIN; I prefer this) such as:
SELECT TOP 2 * FROM table_name INNER JOIN table_name.column_name ON
table_name.column_name2
This way, you will join both the tables where a value in one column matches the value from the other column in both tables.
You can use a for loop for this to select the value for them, or you can use this inside the foreach loop to take out the values for them.
My suggestion
My best method would be to, first just select the data that was ordered using the date.
Then inside the foreach() loop where you will write the data for that select the remaining data for that time. And write it inside that loop.
Code (column_name) won't bother you
And when you will reference the query using ORDER By Time Desc you won't be using the CODE anymore such as WHERE Code = value. And you will get the code for the most recent ones. If you really need the code column, you can filter it out using and if else block.
Reference:
http://technet.microsoft.com/en-us/library/ms190014(v=sql.105).aspx (Inner join)
http://www.w3schools.com/sql/sql_func_first.asp (top; check the Sql Server query)