Currency exchange in database - sql

I am designing a relational database that includes currency exchange rates. My first intuition was to have a currency table that lists all the currencies and holding as attributes the exchange rate for every other currency.
Ex:
Currency Table
id INT
base_currency_code VARCHAR
date DATE
USD DECIMAL
GBP DECIMAL
EUR DECIMAL
I've done a search online on how currency exchange tables are implemented in databases, and everywhere I've looked instead has a table currency_exchange with columns base_currency, non_base_currency (to currency), rate, and date.
Since I can't find an implementation similar to mine and since one post I read said the other implementation is how it's done at the financial company he works at, I assume that the other is superior to mine!
I just don't understand why. Could someone please explain why the other is better?

You want tables like something this:
create table Currencies (
CurrencyId int primary key,
ISO_Code varchar(3),
Name varchar(255)
);
create table CurrencyExchangerate (
CurrencyExchangerateId int primary key,
FromCurrencyId int not null references Currencies(CurrencyId),
ToCurrencyId int not null references Currencies(CurrencyId),
RateDate date not null,
ExchangeRate decimal(20, 10),
constraint unq_currencyexchangerate_3 unique (FromCurrencyId, ToCurrencyId, RateDate)
);

Related

DECIMAL values being converted to INT + 1 on its own

I have a C# app where the user fills a form to store a product in a SQL Server database.
The problem is that every time a product is stored (through the user filling a form), the price (a decimal) is automatically converted to int and has 1 added to it.
I initially thought it was an issue with the app, however, the registration process is pretty simple and I didn't find any error there, so I inserted a row directly from SQL Server and the issue presented itself, so this tells me the issue is in SQL Server, not in the app.
Executing
insert into product (code, description, unit_price, stock, category_code)
values (7, 'Window Cleaner', 20.50, 20, 3)
Results into price being 21.
This is the table definition
CODE INT NOT NULL,
DESCRIPTION VARCHAR(30) NOT NULL,
UNIT_PRICE DECIMAL NOT NULL,
STOCK INT NOT NULL,
CATEGORY_CODE INT NOT NULL
CONSTRAINT PK_PRODUCT PRIMARY KEY(CODE),
CONSTRAINT FK_CATEGORY_CODE FOREIGN KEY (CATEGORY_CODE) REFERENCES Category(CODE),
CONSTRAINT PRODUCT_POSITIVE_VALUES CHECK(UNIT_PRICE > 0 AND CODE >= 0 AND STOCK >= 0)
You have used the following to define your column:
UNIT_PRICE DECIMAL NOT NULL
This has no precision nor scale and will therefore use the default precision (18) and scale (0). The default scale of 0 is effectively an int. So when you insert/update a value the value will get rounded to an int. To solve your problem define your column with the correct precision and scale e.g.
UNIT_PRICE DECIMAL(9,2) NOT NULL
Reference

SQL Debit and Credit tables

I got a database project from my university to finish, but I am stack at the structure of debit and credit table that how to make it in SQL Server, my code is shown here:
create table AcCat
(
CatID smallint Primary Key,
CatName nvarchar(20)
)
Create Table Accounts
(
AcID int Primary key,
AcNumber int,
AcName nvarchar(20),
AcCategory smallint references AcCat(CatID)
)
Create Table Transactions
(
TrnRef bigint primary key identity (1,1),
TrnDate datetime
)
Create Table Voucher
(
VID bigint primary key identity (1,1),
TranRef bigint references Transactions(TrnRef),
AccountNo int references Accounts(AcID),
DrCr nvarchar(2),
Amount money,
Narration nvarchar(100)
)
Create Table Voucher_2
(
V2ID bigint primary key identity (1,1),
V2TranRef bigint references Transactions(TrnRef),
V2DebitAc int references Accounts(AcID),
V2CreditAc int references Accounts(AcID),
Amount money,
Narration nvarchar(100)
)
I don't know above table structure are correct or not, but I am stuck at the Voucher and Voucher_2 tables that which one I should use for my Database.
The tables output is following
My tables Output
Either one seems serviceable. Are you given example queries that should be run over your system? If so, have you tried writing those queries and seeing whether one or other of your structures makes all of those queries harder or simpler? Also, have you considered what integrity constraints you may wish the database to enforce?
For instance, finding the current balance of an account can be reasonably performed using either structure.:
SELECT
ac.AcNumber,
SUM(CASE WHEN DrCr = 'Cr' THEN Amount
ELSE -Amount END) as Balance
FROM
Accounts ac
inner join
Voucher v
on
ac.AcID = v.AccountNo
WHERE
ac.AcNumber = 1010
GROUP BY
ac.AcNumber
SELECT
ac.AcNumber,
SUM(CASE WHEN V2DebitAc = V2CreditAc THEN 0
WHEN V2CreditAc = ac.AciD THEN Amount
ELSE -Amount END) as Balance
FROM
Accounts ac
inner join
Voucher_2 v
on
ac.AcID = v.V2DebitAc or
ac.AcID = v.V2CreditAc
WHERE
ac.AcNumber = 1010
GROUP BY
ac.AcNumber
If all transactions are required to be balanced, how will you ensure that there are always pairs of rows in Voucher that match each other?
If you have to apply interest of other account corrections, what account will you match those with in Voucher_2?
If you haven't been given any scenarios to work against, try to conjure some up like the above and see how well they fit. Without further information though, I'd say either will probably work.
One thing I'd serious recommend fixing though - having all of AcNumber, AccountNum and AcID seems like a recipe for confusion. I'd probably just use AcID everywhere outside of the Accounts table unless you want to go one step further and just use AcNumber as a natural key and use it everywhere and remove AcID from the picture. Certainly I didn't expect (before writing the queries) that I'd find AccountNum also in the picture and it's not the same thing as AcNumber.
Where possible I'd advise using as few names as possible. Ideally, everywhere in your schema that you encounter a particular column name, it should mean the same concept, and you shouldn't encounter the same concept under any other names.

What data type use for taxrate field

What data type should I use for tax rate field in my RoR application. I want it to store only numbers from 0 to 100 and two fixed strings "zw" and "np". Should I use string type and parse it to integer when it's number?
I think, perhaps, you should think about the tax rate as a name of the rate rather than a numeric value.
Create a reference table of tax rates, something like:
create table TaxRates (
TaxRateId int primary key, -- auto_increment/serial/identity
Name varchar(255) not null unique,
Value int, -- NULL if not appropriate
<more columns if necessary>
);
The drop-down list can use this table for the names. Most of the names will be numbers, but that is ok. The actual numeric value will be in the Value field (which you might really want to be a decimal).
Any table that uses a tax rate would have a foreign key reference to TaxRateId.

Designing multiple types of payment schema in SQL?

I've payment system where I can do two types of payment for an order.
Online - Mobile payment
Offline - Cash/ Cheque
I've credited 4 tables, I'm outlining only important columns not everything for simplicity.
List of table Names
Payment
CashPaymentDetails
ChequePaymentDetails
MobilePaymentDetails
Schema Details
CashPaymentDetails
cash_id int
cash_amount decimal(18,2)
ChequePaymentDetails
cheque_id int
cheque_amount decimal(18,2)
cheque_type
MobilePaymentDetails
mobile_id int
mobile_amount decimal(18,2)
Payment
payment_id int
payment_amount decimal(18,2)
fk_cash_id int (foreign key reference to CashPaymentDetails table)
fk_cheque_id (foreign key reference to ChequePaymentDetails table)
fk_mobile_id (foreign key reference to MoblePaymentDetails table)
User can do either cash/cheque/mobile, only one payment mode, this makes my two foreign keys NULL which i feel is overhead because if going forward I've 10 different types of payment method, 9 Fk references will be NULL.
Payment
Payment_id payment_amount fk_cash_id fk_cheque_id fk_mobile_id
1 300 1 NULL NULL
2 200 NULL 1 NULL
3 400 NULL NULL 1
what should be an optimal design to create this schema?
Create table for PaymentMethod and refer its PK in Payments table then according to payment method you can make appropriate entry in respective tables of payment method. I have also added Payment_id in [CashPaymentDetails], [ChequePaymentDetails] & [MobilePaymentDetails] tables.
Schema Details
[PaymentMethods]
Payment_Method_id int
Payment_Method_Description varchar(50) -- ("cash", "cheque", "mobile" etc)
[Payment]
Payment_id int
Payment_Method_id int
payment_amount decimal(18,2)
[CashPaymentDetails]
cash_id int
payment_id int
cash_amount decimal(18,2)
[ChequePaymentDetails]
cheque_id int
payment_id int
cheque_amount decimal(18,2)
cheque_type
[MobilePaymentDetails]
mobile_id int
payment_id int
mobile_amount decimal(18,2)
Your design is fine (not the only choice, but fine). I would add a constraint to the table to ensure that one -- and exactly one -- payment type is implemented:
alter table payment
add constraint chk_one_payment
check ((fk_cash_id is not null and fk_cheque_id is null and fk_mobile_id is null) or
(fk_cash_id is null and fk_cheque_id is not null and fk_mobile_id is null) or
(fk_cash_id is null and fk_cheque_id is null and fk_mobile_id is not null)
);
There are other ways to represent a one-of relationship. For instance, you could just have:
PaymentType (one of "cash", "cheque", "mobile")
PaymentAmount
CheckType (if applicable)
The different types of payments have almost the same columns, so this is very reasonable in your case. For some one-of relationships, the different types have very different columns, and want to be in their own tables.
My advice is this.
On the Payment table, remove all those foreign keys and add these 2 fields.
processor_type enum['bank', 'cheque', 'card']
transaction_id fk to the processor table.
With this, each time you update/add a new processor, you just need to update the enum such that it takes the new set of payment processors. The transaction_id is a foreign key to the appropriate table depending on the processor_type.
If you are using laravel, you can make use of polymorphic relationships
That's my suggestion.

SQL - Create table in SQL

Please guide me if I'm on right track.
I'm trying to create database schema for Mobile Bill for a person X and how to define PK, FK for the table Bill_Detail_Lines.
Here are the assumptions:
Every customer will have a unique relationship number.
Bill_no will be unique as it is generated every month.
X can call to the same mobile no every month.
Account_no is associated with every mobile no and it doesn't change.
Schema:
table: Bill_Headers
Relationship_no - int, NOT NULL , PK
Bill_no - int, NOT NULL , PK
Bill_date - varchar(255), NOT NULL
Bill_charges - int, NOT NULL
table: Bill_Detail_Lines
Account_no - int, NOT NULL
Bill_no - int, NOT NULL , FK
Relationship_no - int, NOT NULL, FK
Phone_no - int, NOT NULL
Total_charges - int
table: Customers
Relationship_no - int, NOT NULL, PK
Customer_name - varchar(255)
Address_line_1 - varchar(255)
Address_line_2 - varchar(255)
Address_line_3 - varchar(255)
City - varchar(255)
State - varchar(255)
Country - varchar(255)
I would recommend having a primary key for Bill_Detail_Lines. If each line represents a total of all calls made to a given number, then the natural PK seems to be (Relationship_no, Bill_no, Phone_no), or maybe (Relationship_no, Bill_no, Account_no).
If each line instead represents a single call, then I would probably add a Line_no column and make the PK (Relationship_no, Bill_no, Line_no).
Yes, as for me, everything looks good.
I have to disagree, there's a couple of 'standards' which aren't being followed. Yes the design looks ok, but the naming convention isn't appropriate.
Firstly, table names should be singular (many people will disagree with this).
If you have a single int, PK on a table, the standard is to call it 'ID', thus you have "SELECT Customer.ID FROM Customer" - for instance. You also then fully qualify the FK columns, for instance: CustomerID on Bill_Headers instead of Relationship_no which you then have to check in the table definition to remember what it's related to.
Something I also always keep in mind, is to make the column header as clear and short as possible without obfuscating the name. For instance, "Bill_charges" on Bill_Headers could just be "Charges", as you're already on the Bill_Header(s) (<- damn that 's'), same goes for Date, but date could be a bit more descriptive, CreatedDate, LastUpdatedDate, etc...
Lastly, beware of hard-coding multiple columns where one would suffice, same other way around. Specifically I'm talking about:
Address_line_1 - varchar(255)
Address_line_2 - varchar(255)
Address_line_3 - varchar(255)
This will lead to headaches later. SQL does have the capability to store new line characters in a string, thus combining them to one "Address - varchar(8000)" would be easiest. Ideally this would be in a separate table, call it Customer_Address with int "CustomerID - int PK FK" column where you can enter specific information.
Remember, these are just suggestions as there's no single way of database design that everyone SHOULD follow. These are best practices, at the end of the day it's your decision to make.
There are a few mistakes:
Realtionship_no and Bill_no are int. Make sure that the entries are within the range of integer. It is better to take them as varchar() or char()
Bill_date should be in data type Date
In table Bill_Detail_Lines also, it is better to have Account_no as varchar() or char() because of the long account no. And the same goes with Phone_no.
Your Customers table is all fine except that you have taken varchar() size as 255 for City State and Country which is too large. You can work with smaller size also.