join two records from the same table - ms-access

(This is in access)
I have a table with all the history of the wages of my workers. Each record has an starting date in which the employee started receiving that wage and a starting date in which we started reporting this wage. Why?, legal stuff.. (Sometimes the starting date is older than the date we started reporting it)
-------------------------------------------------------
|WorkerID|StartingDate|ReportingDate|Salary|
-------------------------------------------------------
| 001 | 01/01/2015 | 01/01/2015 |10,000|
| 001 | 01/01/2016 | 01/02/2016 |15,000|
-------------------------------------------------------
So if I want to make a check for the worker 001 on 01/01/2016 it should be $15,000, but i have to report $10,000. So now I need a query that tells me the wage I should pay and the wage I should Report, just like this:
------------------------------------------------------------
|WorkerID|StartingDate|ReportingDate|PaySalary|ReportSalary|
------------------------------------------------------------
| 001 | 01/01/2016 | 01/02/2016 | 15,000 | 10,000 |
------------------------------------------------------------
The table is called Wages_History and I donĀ“t have a clue of how to start the query... Thanks!

If I understand correctly, this is a simple where filter:
select *
from wages_history
where reporting_date > starting_date;
If this is the case, then I would suggest that you devote some effort to learning SQL . . . there are good books, tutorials, and courses available.
EDIT:
If you also want the previous salary:
select wh.*,
(select top 1 wh2.salary
from wages_history wh2
where wh2.worker_id = wh.worker_id and
wh2.starting_date < wh.starting_date
order by wh2.starting_date desc
) as prev_salary
from wages_history wh
where reporting_date > starting_date;

Related

Using an SQL View to dynamically place field data in buckets

I have a complex(?) SQL query I am needing to build. We have an application that captures a simple data set for multiple clients:
ClientID | AttributeName | AttributeValue | TimeReceived
----------------------------------------------------------------
002 | att1 | 123.98 | 23:02:00 02-03-20017
----------------------------------------------------------------
003 | att2 | 987.2 | 23:02:00 02-03-20017
I need to be able to return a single record per client that looks something like this
Attribute | Hour_1 | Hour_2 | Hour_x |
--------------------------------------
att1 120.67 |
--------------------------------------
att2 | 10 | 89.3 |
The hours are to be determined by a time provided to the query. If the time was 11:00 on 02-03-20017, then hour 1 would be from 10-11 on 02-03-20017, and hour 2 from 9-10 on 02-03-20017. Attributes will be allocated to these hourly buckets based on the hour/date in their time stamp (not all buckets will have data). There will be a limit on the number of hours allocated in a single query. In summary, there are possibly 200-300 attributes and hourly blocks of up to 172 hours. To be honest I am not really sure where to start to build a query like this. Any guidance appreciated.

Use Max date to create a date range

I need to create a date range in a table that houses transaction information. The table updates sporadically throughout the week from a manual process. Each time the table is updated transactions are added up to the previous Sunday. For instance, the upload took place yesterday and so transactions were loaded through last Sunday (Feb 26th). If it had been loaded on Wednesday it would still be dated for Sunday. The point is that I have a moving target with my transactions and also when the data is loaded to the table. I am trying to fix my look back period to the date of the latest transaction then go three weeks back. Here is the query that I came up with:
SELECT distinct TransactionDate
FROM TransactionTABLE TB
inner join (
SELECT distinct top 21 TransactionDate FROM TrasactionTABLE ORDER BY TransactionDate desc
) A on TB.TransactionDate = A.TransactionDate
ORDER BY TB.TransactionDate desc
Technically this code works. The problem that I am running into now is when there were no transactions on a given date, such as bank holidays (in this case Martin Luther King Day), then the query looks back one day too far.
I have tried a few different options including MAX(TransactionDate) but if I use that in a sub-query or CTE then use the new value in a WHERE statement as a reference I only get the max value or the value I subtract that statement by. For instance if I say WHERE TransactionDate >= MAX(TransactionDate)-21 and the max date is Feb 26th then the result is Feb 2nd instead of the range of dates from Feb 2nd through Feb 26th.
IN SUMMARY, what I need is a date range looking three weeks back from the date of the latest transaction date. This is for a daily report so I cannot hardcode the date in. Since I am also using Excel Connections the use of Declare statements is prohibited.
Thank you StackOverflow gurus in advance!
You could use something like this:
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (21)
[Date]=convert(date,dateadd(day, row_number() over (order by (select 1))-1
, dateadd(day,-20,(select max(TransactionDate) from t) ) ) )
from n as deka
cross join n as hecto
order by [Date]
)
select Date=convert(varchar(10),dates.date,120) from dates
rextester demo: http://rextester.com/ZFYV25543
returns:
+------------+
| Date |
+------------+
| 2017-02-06 |
| 2017-02-07 |
| 2017-02-08 |
| 2017-02-09 |
| 2017-02-10 |
| 2017-02-11 |
| 2017-02-12 |
| 2017-02-13 |
| 2017-02-14 |
| 2017-02-15 |
| 2017-02-16 |
| 2017-02-17 |
| 2017-02-18 |
| 2017-02-19 |
| 2017-02-20 |
| 2017-02-21 |
| 2017-02-22 |
| 2017-02-23 |
| 2017-02-24 |
| 2017-02-25 |
| 2017-02-26 |
+------------+
I just found this for looking up dates that fall within a given week. The code can be manipulated to change the week start date.
select convert(datetime,dateadd(dd,-datepart(dw,convert(datetime,convert(varchar(10),DateAdd(dd,-1/*this # changes the week start day*/,getdate()),101)))+1/*this # is used to change the week start date*/,
convert(datetime,convert(varchar(10),getdate(),21))))/*also can enter # here to change the week start date*/
I've included a screenshot of the results if you were to include this with a full query. This way you can see how it looks with a range of dates. I did a little manipulation so that the week starts on Monday and references Monday's date.
Since I am only looking back three weeks a simple GETDATE()-21 is sufficient because as the query moves forward through the week it will look back 21 days and pick the Monday at the beginning of the week as my start date.

Housing Society management system database structure

I am designing billing structure for housing society yesterday I googled and gone through banking billing structure and designed my database structure but I am not sure whether this would be correct. So I am putting my billing database structure.
Please tell me if I am wrong any where or any changes has to be done in my database structure.
And one more questions where I have to post society balance (debit, credit )like eg expense Bldg insurance and income like Adv board hoarding and also not sure about balance audit trail (having it in transaction table of separate table with transaction id as FK).
Please note all table will have by default have created,modified time, by and ip address
Table billingstatement
id | description | amount | Bill Month | userId | societyId
1 | Maint Chrg 1000 sqft x 5 per sqft | 5000 | Aug-16 | 1001 | 101
2 | Water Charges | 200 | Aug-16 | 1001 | 101
3 | Construction Charges | 300 | Aug-16 | 1001 | 101
4 | Reserved Parking chrgs | 500 | Aug-16 | 1001 | 101
Table Accounts
id | balance(current bal) | societyId | modifiedTime |
1 | -6000 | 101 | 2016-01-01 21:01:01 |
2 | -5000 | 101 | 2016-01-01 21:01:01 |
3 | 1000 | 101 | 2016-01-01 21:01:01 |
Table transaction
id | amount | balance | trans_type | trans_time | account_id |
1 | 6000 | 0 | 1 | 2016-01-01 21:01:01 | 1 |
2 | 5500 | -6000 | 1 | 2016-02-01 21:01:01 | 2 |
tran_type :- 1 = Payment by user, 2 = Income to society, 3 = Expense to society
Table map_account_user
map_id | account_id | user_id
1 | 2 | 1001
If account mapping is not present then it means it is a society account and not a user account.
Reference :-
billing banking desing
banking project sample
I have a hesitation with storing an aggregate with the entity. Unless the aggregate is very difficult to calculate, you should always account for these by examining the details.
I'm assuming you are designing a relational database. In a relational database, you normalize the data.
I'm having trouble following your database design because you have too many different fields called id. Each id field should get a unique name, so people can tell what the different id fields represent.
Let's start with the Transaction table. Generally table names are singular. I capitalize table names and column names. You don't have to follow that convention.
Transaction
-----------
Transaction ID
Transaction Type
User ID
Society Account
Transaction Amount
Transaction Time Stamp
...
Transaction ID is an auto-incrementing integer. It is also the primary (clustering) key to the Transaction table. Transaction Type is 1 = Payment by user, 2 = Income to society, 3 = Expense to society. I'm not sure what the difference is between Transaction Type 1 and Transaction Type 2.
Either the User ID or the Society Account column is filled in. The User ID column is filled in for Transaction Type 1 and the Society Account column is filled in for Transaction Types 2 and 3. The not filled in column is set to null.
Transaction Amount is always a positive value. Your code will subtract the Transaction Amount from the Society Account for Transaction Type 3.
You will create a unique index for (User ID, Transaction Time Stamp descending, Transaction ID) and a unique index for (Society Account, Transaction Time Stamp descending, Transaction ID). This allows you to quickly get all the transactions for a user or society account, for a given month.
Next, let's look at the UserAccountBalance table.
UserAccountBalance
------------------
User ID
Balance Year and Month
Balance Amount
...
The primary key to this table is (User ID, Balance Year and Month descending). You maintain the historical balances for each month for each User ID. This allows an auditor to verify the balances by running queries against the Transaction table.
Next, let's look at the SocietyAccountBalance table.
SocietyAccountBalance
---------------------
Society Account
Balance Year and Month
Balance Amount
...
This table is similar to the UserAccountBalance table, but for Society accounts.
Next, let's look at the Billing table
Billing
-------
User ID
Billing Year and Month
Billing Type
Square Feet
Charge per Square Foot
Total Charge
...
The primary key is (User ID, Billing Year and Month descending, Billing Type). I'm assuming that you only get one billing charge per billing type per month.
Billing Type is 1 = Maintenance Charge, 2 = Water Charge, 3 = Construction Charge, 4 = Reserved Parking Charge. You can generate the text on the bill from the values in this table, so there's no need to store the text in the database. The Square Feet and Charge per Square Foot columns are filled in for Billing Type 1, otherwise they are null.
You still have to match up the payments with the billings, but this should be enough to get you started on the right path.
The structure works. I would change the id naming a bit.
account_id is referenced in some places
but in the account table it is Id.
I would make it account_id in the Account table. This makes it easier to locate where you can join for the users of the database. Every place you call it "Account_Id" is should be the same Account_Id with a single master table that generates it.
Really appreciated for your efforts. You reference on banking system is really a best approach. I would like to provide you some ideas which may help you if you feel it is better for you.
Let's start. If you use your description column's data:
{Water Charges
Construction Charges
Reserved Parking chrgs}
as a new columns, your no of rows will be decreased and since you can have efficient data maintenance. For each userId you can have a single row of data rather than maintaining four rows. Just verify below provided example.
For each sq ft you can have a description column separately.
id | userId | societyId | BillMonth | MaintChrg | WaterCharges | ConstructionCharges | ReservedParkingCharges | Description
1 | 1001 | 101 | Aug-16 | 5000 | 200 | 300 | 500 | Maint Chrg 1000 sqft x 5 per sqft
2 | 1002 | 101 | Aug-16 | 4000 | 200 | 300 | 500 | Maint Chrg 900 sqft x 5 per sqft
3 | 1003 | 102 | Aug-16 | 5000 | 200 | 300 | 500 | Maint Chrg 900 sqft x 5 per sqft
For you doubt on debit and credit use:
debit as expenseBldginsurance
credit as Adv board hoarding
You can also add may other columns like user name, No of peoples, electricity charges, etc.

SQL statement greater issue

I'm building a small gym training system and I'm currently having a problem with an SQL query. I need to get the names of all customers who are more than ten kilos heavier than their target weight. Here are my tables.
Person: PersonID | Name | DOB | Email | Gender
Item: ItemID | Name | Portion | kCal | Fat
Training: TrainingID | Person_ID | StartDate | StartWeight | TargetWeight | CurrentWeight
Now I can get the list of people who are heavier than their target weight, but I specifically need to receive customers who are more than 10 kg heavier than their target weight. I know it's probably basic but I just couldn't get my head around it for somehow. Any help would be appreciated.
Thank you
select p.*
from person p
join training t on t.person_id = p.personid
where t.currentweight - t.targetweight > 10

Continue most recent value over a time range

I have this existing schema where a "schedule" table looks like this (very simplified).
CREATE TABLE schedule (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(45),
start_date date,
availability int(3),
PRIMARY KEY (id)
);
For each person it specifies a start date and percentage of work time available to spent on this project. That availability percentage implicitly continues until a newer value is specified.
For example take a project that lasts from 2012-02-27 to 2012-03-02:
id | name | start_date | availability
-------------------------------------
1 | Tom | 2012-02-27 | 100
2 | Tom | 2012-02-29 | 50
3 | Ben | 2012-03-01 | 80
So Tom starts on Feb., 27nd, full time, until Feb, 29th, from which on he'll be available only with 50% of his work time.
Ben only starts on March, 1st and only with 80% of his time.
Now the goal is to "normalize" this sparse data, so that there is a result row for each person for each day with the availability coming from the last specified day:
name | start_date | availability
--------------------------------
Tom | 2012-02-27 | 100
Tom | 2012-02-28 | 100
Tom | 2012-02-29 | 50
Tom | 2012-03-01 | 50
Tom | 2012-03-02 | 50
Ben | 2012-02-27 | 0
Ben | 2012-02-28 | 0
Ben | 2012-02-29 | 0
Ben | 2012-03-01 | 80
Ben | 2012-03-02 | 80
Think a chart showing the availability of each person over time, or calculating the "resource" values in a burndown diagram.
I can easily do this with procedural code in the app layer, but would prefer a nicer, faster solution.
To make this remotely effective, I recommend creating a calendar table. One that contains each and every date of interest. You then use that as a template on which to join your data.
Equally, things improve further if you have person table to act as the template for the name dimension of your results.
You can then use a correlated sub-query in your join, to pick which record in Schedule matches the calendar, person template you have created.
SELECT
*
FROM
calendar
CROSS JOIN
person
LEFT JOIN
schedule
ON schedule.name = person.name
AND schedule.start_date = (SELECT MAX(start_date)
FROM schedule
WHERE name = person.name
AND start_date <= calendar.date)
WHERE
calendar.date >= <yourStartDate>
AND calendar.date <= <yourEndDate>
etc
Often, however, it is more efficient to deal with it in one of two other ways...
Don't allow gaps in the data in the first place. Have a nightly batch process, or some other business logic that ensures all relevant dat apoints are populated.
Or deal with it in your client. Return each dimension in you report (data, and name) as seperate data sets to act as your templates, and then return the data as your final data set. Your client can itterate over the data and fill in the blanks as appropriate. It's more code, but can actually use less resource overall than trying to fill-the-gaps with SQL.
(If your client side code does this slowly, post another question examining that code. Provided that the data is sorted, this is acutally quite quick to do in most languages.)