How to manage multiple currencies in the database - sql-server

If I have different multiple payroll disbursements based on the company location, the employee contract type and other criteria:
So
Some have their salaries divided into parts the first in USD and the second in Local cur.
Ex: Employee 343 receive his salary as following: 200 USD & 3000 EGP (The local currency).
EX: Employee 672 receive his salary as following: 200 USD & 200 EUR (The local currency).
Some have their salaries just in one currency (the local).
Ex: Employee 532 receive his salary as following: 5000 EGP.
So We have multiple currencies for the salaries of the company based on the location and other business rules.
What 's the most proper way to save the salaries of the employees with these variations in DB so that It's easy to retrieve, process and scale.
If I use one table so I will have many columns and I have to add new columns every time a new branch for the company is initiated.
Like this:
Sal_USD | Sal_EGP | Sal_Eur
Is there an elegant way to handle this?

The correct way is always to support an infinite numbers of connections. So create a table with salary an another with currency.
I think 3tables would do the jobb
Employee (the one you have now)
- EmployeeID
Salary
- SalaryID
- EmployeeID
- CurrencyID
- Wage
- Exchangerate ?
CurrencyID
- CurrencyID
- Name (USD/GDP/EUR....)
Then you simply join them in.

Create a column CurrencyCode and use 2 rows for an employee that has salary paid in 2 currencies.

Related

LAG and/or LEAD alternative without window function in Pstgresql

Well I'm using Postgresql(but it won't matter if you can advise a solution in any SQL syntax), I have a table like
employee
department
salary
1
sales
30,000
2
sales
25,000
3
marketing
45,000
4
marketing
55,000
so on...
What I want to achieve is:
employee
department
salary
difference
1
sales
30,000
0/null
2
sales
25,000
5,000
3
marketing
45,000
0/null
4
marketing
55,000
10,000
So technically I want to extract the value difference of consecutive rows, however I can't use the window functions (I don't know why, but it is must to avoid in this challenge)
in a perfect world, we'd be able to do lag() or lead() functions partitioned by department name and store the value difference in other column, but I don't know how to do it without them.
I tried subqueries multiple ways, but every time I ended up having NULL or 0 in new a column
You can use a self-join to table itself and join each employee with the previous row within the same department.
SELECT t1.employee, t1.department, t1.salary, ABS(t2.salary - t1.salary) AS difference
FROM tab t1
LEFT JOIN tab t2
ON t1.department = t2.department AND t1.employee = t2.employee +1

Need a SQL query to get data from SQL Server database for a given period with certain condition

I have a SQL Server database with a table dbo.sales with 7 columns.
First column contains different sales person names, on column 2 to 6 other information, on column 7, sales average.
Question: what I need is a query to get all sales person details (all seven columns in Excel) if their sales average is more than 60% between a given date.
For example: in my database, I have data from 01/05/2016 to 31/05/2016, if I enter a period in my Excel sheet between 25/05/2016 to 31/05/2016 and my required average for ex. 60% (should be changed as per my need), then I need all the sales person details who continuously have sales average of more than 60% between 25 to 31st May 2016.
If a sales man average was dropped below 60% on 28th May, then I don't want to see him on my report. In simple words, I need all sales person who continuously hitting 60% or more on average sales within my search period.
Not sure if the sales period date is within the table, but if it is, that query should work for you:
;WITH PeriodSales as (
SELECT * FROM Sales
WHERE SalseDate between #StartDt and #EndDt)
SELECT * FROM PeriodSales
WHERE SalesPerson not in (
SELECT SalesPerson FROM PeriodSales
WHERE CASE WHEN IsNumeric(salesavg) = 1
THEN CAST(salesavg as Decimal) ELSE 0 END <= 60.
);

DataStage recursion

I have to find a leader of a group and update employee's leader. I am not sure how to proceed with this in DataStage.
I have an employee table as shown below
Emp_id mgr_id leader_id
1 100 400
101 201 500
3 202 600
I get a file to update employee table when an employee changes group. Change code = CHG means it is a job/group change.
I do an equi join between file and employee table and can update manager id. At the same time, I need to find a leader. I need to get all the employees who report to that top level leader and use as the leader id's for every employee.
File:
emp_id mgr_id chg_cd
1 102 CHG
101 301 CHG
File Row 1: There is change in manager for emp_id = 1; need to update mgr_id, leader_id in employee table
File Row 2: There is change in manager for emp_id = 102, need to change mgr_id and leader_id for in employee table
Can you please suggest me on how to proceed with this in DataStage?
ok this problem requires a solution with recursion. As DataStage has no way to do it (if the levels between managers and leaders are variable).
So load the data into a database table and use recursive SQL to query it - this will provide you the solution you are asking for.
Example:
Extract all leaders with their business units they manage inculding different levels) with the recursive SQL statement and use this data in da DataStage lookup to enrich the file data.

Crystal Report do not do the sum on Database "Cache"

I am using Crystal report to do a sum over 3 columns. The table structure looks like:
table #test (Country VARCHAR(10), Name VARCHAR(10), Weight VARCHAR(10), Qty INT)
I wrote a query in the crystal command pane when I do the connection:
SELECT Country, SUM(Qty) As Qty, Name, Weight FROM #test GROUP BY Country, Name, Weight
I should get something like:
CANADA 2 John 200
US 1 John 160
US 2 Mike 180
US 6 Sam 90
However, the crystal report does not sum the field, instead it pulls every single row, and the result looks like I write the query:
SELECT Country, Qty, Name, Weight FROM #test
CANADA 1 John 200
CANADA 1 John 200
US 1 John 160
US 2 Mike 180
US 3 Sam 90
US 3 Sam 90
By the way, the backend database is called "Cache". It might be due to there are some hidden characters, but I cannot see them. I have used replace (char(10)), replace (char(13) and trim to try to clean.
I also try to pull the table column directly without writing the query, but I do not know how to sum three columns (Country, Name and Weight). I only know how to sum one column. By the way, the request do not want the details, only the sum over these three columns;
First group by country.
Create one more group by quantity
Create one more group by name
Place weight in details and take the sum for all 3 groups if you need or only particular group
Supress tje details.

Best structure for inventory database

I want to create a small database for my inventory but I have some problems on picking a structure. The inventory will be updated daily at the end of the day.
The problem I am facing is the following.
I have a table for my products, having an
id, name, price, quantity.
Now I have another table for my sales, but there is my problem. What kind of fields do I need to have. At the end of the day I want to store a record like this:
20 product_x $ 5,00 $ 100,-
20 product_y $ 5,00 $ 100,-
20 product_z $ 5,00 $ 100,-
20 product_a $ 5,00 $ 100,-
-------------------------------------------------
$ 400,-
So how do I model this in a sales record. Do I just create a concatenated record with the product id's comma separated.
Or is there another way do model this the right way.
This is a model which supports many aspects,
Supports Sites, Locations and Warehouses etc.
Supports Categorization and Grouping
Support Generic Product (Ex. "Table Clock" and specific product "Citizen C123 Multi Alarm Clock" )
Also support Brand Variants (by various manufacturers)
Has CSM (color / size / model support) Ex. Bata Sandles (Color 45 Inch Blue color)
Product Instances with serials (such as TVs , Refrigerators etc.)
Lot control / Batch control with serial numbers.
Pack Size / UOM and UOM Conversion
Manufacturer and Brands as well as Suppliers
Also included example transaction table (Purchase order)
There are many other transaction types such as Issues, Transfers, Adjustments etc.
Hope this would help. Please let me know if you need further information on each table.
Cheers...!!!
Wajira Weerasinghe.
Sites
id
site_code
Site_name
Warehouse
id
site_id
warehouse_code
warehouse_name
Item Category
id
category_code
category_name
Item Group
id
group_code
group_name
Generic Product
id
generic_name
Product
id
product_code
category_id
group_id
brand_id
generic_id
model_id/part_id
product_name
product_description
product_price (current rate)
has_instances(y/n)
has_lots (y/n)
has_attributes
default_uom
pack_size
average_cost
single_unit_product_code (for packs)
dimension_group (pointing to dimensions)
lot_information
warranty_terms (general not specific)
is_active
deleted
product attribute type (color/size etc.)
id
attribute_name
product_attribute
id
product_id
attribute_id
product attribute value (this product -> red)
id
product_attribute_id
value
product_instance
id
product_id
instance_name (as given by manufacturer)
serial_number
brand_id (is this brand)
stock_id (stock record pointing qih, location etc.)
lot_information (lot_id)
warranty_terms
product attribute value id (if applicable)
product lot
id
lot_code/batch_code
date_manufactured
date_expiry
product attribute value id (if applicable)
Brand
id
manufacturer_id
brand_code
brand_name
Brand Manufacturer
id
manufacturer_name
Stock
id
product_id
warehouse_id, zone_id, level_id, rack_id etc.
quantity in hand
product attribute value id (if applicable) [we have 4 red color items etc.]
Product Price Records
product_id
from_date
product_price
Purchase Order Header
id
supplier_id
purchase_date
total_amount
Purchase Order Line
id
po_id
product_id
unit_price
quantity
Supplier
id
supplier_code
supplier_name
supplier_type
product_uom
id
uom_name
product_uom_conversion
id
from_uom_id
to_uom_id
conversion_rule
I'd have a table with a row per item per day - store the date, the item ID, the quantity sold, and the price sold at (store this even though it's also in the product table - if that changes, you want the value you actually sold at preserved). You can compute totals per item-day and totals per day in queries.
Tables:
create table product (
id integer primary key,
name varchar(100) not null,
price decimal(6,2) not null,
inventory integer not null
);
create table sale (
saledate date not null,
product_id integer not null references product,
quantity integer not null,
price decimal(6,2) not null,
primary key (saledate, product_id)
);
Reporting on a day:
select s.product_id, p.name, s.quantity, s.price, (s.quantity * s.price) as total
from product p, sale s
where p.id = s.product_id
and s.saledate = date '2010-12-5';
Reporting on all days:
select saledate, sum(quantity * price) as total
from sale
group by saledate
order by saledate;
A nice master report over all days, with a summary line:
select *
from (
(select s.saledate, s.product_id, p.name, s.quantity, s.price, (s.quantity * s.price) as total
from product p, sale s
where p.id = s.product_id)
union
(select saledate, NULL, 'TOTAL', sum(quantity), NULL, sum(quantity * price) as total
from sale group by saledate)
) as summedsales
order by saledate, product_id;
Try modelling your sales as a transaction - with a "header", i.e. who sold to, when sold, invoice # (if applicable), etc. and "line items", i.e. 20 * product_x # $5 = $100. The safest approach is to avoid relying upon prices etc. from the products table - as these will presumably change over time, and instead copy much of the product information (if not all) into your line item - so even when prices, item descriptions etc. change, the transaction information remains as was at the time the transaction was made.
Inventory can get quite complex to model. First you need to understand that you need to be able to tell the value of the inventory onhand based on what you paid for it. This means you cannot rely on a product table that is updated to the current price. While you might want such a table to help you figure out what to sell it for, there are tax reasons why you need to know the actual vlaue you paid for each item in the warehouse.
So first you need the product table (you might want to make sure you have an updated date column in this, it can be handy to know if your prices seem out of date).
Then you need a table that stores the actual warehouse location of each part and the price at purchase. If the items are large enough, you need a way to individually mark each item, so that you know what was taken out. Usually people use barcodes for that. This table needs to be updated to record that the part is no longer there when you sell it. I prefer to make the record inactive and have a link to my sales data to that record, so I know exactly what I paid for and what I sold each part for.
Sales should have at least two tables. One for the general information about the sale, the customername (there should also be a customer table most of the time to get this data from), the date, where it was shipped to etc.
Then a sales detail table that includes a record for each line item in the order. Include all the data you need about the part, color, size, quantity, price. This is not denormalizing, this is storing historical data. The one thing you do not want to do is rely on the prices in the product table for anything except the inital entry to this table. You do not want to do a sales report and have the numbers come out wrong becasue the product prices changed the day before.
Do not design an inventory database without consulting with an accountant or specialist in taxes. You also should do some reading on internal controls. It is easy to steal from a company undetected that has not done their work on internal controls in the database.
I think you need a table with fields showing the transaction properties per customer
OR
a table with fields - date, product(foreign), quantity - this way you'll have no problem with new products
Try multiple tables with links
table_products
id
name
table_product_sales
id
product_id
quantity
price_per
transaction_time AS DATETIME
SELECT table_product_sales.*, table_product.name
FROM table_product
JOIN table_product_sales
ON table_product_sales.product_id = table_product.id
GROUP BY DATE(transaction_time)
Haven't tried it but will something like that work? That allows you to keep each transactions separate so you can query things like average number sold per sale, total sold per date, total sales each day, etc.

Resources