How do I populate Dim_tbls from a relational source?
These example tables are given:
tbl_sales: id_sales, fk_id_customer, fk_id_product, country, timestamp
tbl_customer: id_customer, name, adress, zip, city
tbl_product: id_product, price, product
My goal is to get these attributes into a start-schema. The problem I have is the logic behind loading the dimension tables. I mean, what data would I load into the Dim_Product? All the products that are in tbl_product? But how would I know how many Sales are done with a specific product?
Analysis I would like to do are:
How many people bought product x.
How many sales are made from city x.
How many sales were made between Time x and y.
Example data:
tbl_sales: id_sales | fk_id_customer | fk_id_product | country | timestamp
1 | 2 | 1 | UK | 19.11.2013 10:23:22
2 | 1 | 2 | FR | 20.11.2013 06:04:22
tbl_customer: id_customer | name | adress | zip | city
1 | Frank|Street X| 211 | London
2 | Steve|Street Y| 431 | Paris
tbl_customer: id_product| Price | product
1 | 100,00| Hammer
2 | 50,00| Saw
Let's start with a very simple star schema model; for example, I assumed you don't need to worry about handling changes to dimensions' attributes.
factSales
DateKey
CustomerKey
ProductKey
Counter (=1; this is a factless fact table)
dimDate
DateKey
Date
Year
Quarter
Month
...
dimCustomer
CustomerKey
Name
Address
Zip
City
dimProduct
ProductKey
Name
Price (if it changes, you need move it to factSales)
How many people bought product x.
SELECT DISTINCT CustomerKey
FROM factSales
WHERE ProductKey IN ( SELECT ProductKey
FROM dimProduct
WHERE Name = 'Product X' )
How many sales are made from city x.
SELECT SUM(Counter)
FROM factSales
WHERE CustomerKey IN ( SELECT CustomerKey
FROM dimCustomer
WHERE City = 'City X' )
How many sales were made between Time x and y.
SELECT SUM(Counter)
FROM factSales
WHERE DateKey IN ( SELECT DateKey
FROM dimDate
WHERE Date BETWEEN DateX AND DateY )
Related
Env: Oracle APEX v5.1 with Oracle 12c Release 2
Firstly, I have created an Interactive Grid that isn't based off an underlying table as I will process this manually using PL/SQL.
I have been using the following as a guide:
https://apex.oracle.com/pls/apex/germancommunities/apexcommunity/tipp/6361/index-en.html
I basically have the following query:
select
level as id,
level as grid_row,
null as product,
null as product_item
from dual connect by level <= 1
Concentrating on just the product and product_item columns where the product_item column will be a readonly column and only the product number can be entered, I would like to achieve the following:
Product Product Item
---------- -------------
123456 123456-1
123456 123456-2
556677 556677-1
654321 654321-1
654321 654321-2
654321 654321-3
123456 123456-3
From the above, as the user types in the Product and then tabs out of the field, I would like a DA to fire that will add the sequence of "-1" to the end of that product number. Then is the user then adds another row within the IG and enters the same product number, I then want it to append "-2" to the end of it.
Only when the product changes number, I need the sequence to reset to "-1" for that new product as per 556677 and so forth.
Other scenarios that should also be taken into consideration are as follows:
From above IG, the user entered 123456 again but this should calculate that the next sequence for 123456 is "-3"
The same needs to be catered for, when a Product is removed from the IG but to always look at the max sequence number for that product.
I was thinking of possibly using APEX_COLLECTIONS as a means of storing what is currently in the grid, since no changes have been committed to the database.
Assuming you have a collection of product values (in this case, I am using the built-in SYS.ODCINUMBERLIST which is a VARRAY data type) then the SQL for your output would be:
SELECT id,
id AS grid_row,
product,
product || '-' || ROW_NUMBER() OVER ( PARTITION BY product ORDER BY id )
AS product_item
FROM (
SELECT ROWNUM AS id,
COLUMN_VALUE AS product
FROM TABLE(
SYS.ODCINUMBERLIST(
123456,
123456,
556677,
654321,
654321,
654321,
123456
)
)
)
ORDER BY id
Output:
ID | GRID_ROW | PRODUCT | PRODUCT_ITEM
-: | -------: | ------: | :-----------
1 | 1 | 123456 | 123456-1
2 | 2 | 123456 | 123456-2
3 | 3 | 556677 | 556677-1
4 | 4 | 654321 | 654321-1
5 | 5 | 654321 | 654321-2
6 | 6 | 654321 | 654321-3
7 | 7 | 123456 | 123456-3
db<>fiddle here
As you mentioned, the data you enter is not saved into the DB whilst you are inserting your products, so it is not in fact stored anywhere.
So you cannot go check if that value already exists and enter a -2 or other.
Some things to consider would be to maybe save the values into a temp table so you can then have a function go check how many product_item like 123456-% are in there and use that number +1 as your new product_item.
Or you could go the even harder way and do it all with javascript. For this you will need to somehow get all records in the IG, go through them all and see how many occurences of 123456 you have and then insert 123456-(no of occurences + 1).
I am working on a bill customization project in which customer requirement is described below:
First there is an Invoice details table:
e.g. (Table Structure and values)
Particulars InvoiceNo InvoiceDate InvoiceQty UnitOfMeasurement Rate Amount Currency
Apple I-90 2-12-2014 1000 Kg 8 8000 INR
It can contain multiple entries ..but the InvoiceNo will be different
Now another table contains an invoice's Damage Details (for insurance purposes)
e.g. (Invoice Damage Details Table):
Particular InvoiceNo invoiceqty AffectedQty UOM Rate Remarks
Apple I-90 1000 100 Kg 8 Pressed so waste
Apple I-90 1000 500 Kg 8 Smelled And waste
Now a Particular can contain different reasons for different quantity as mentioned above.
The last and final table contains all Information and the customer is demanding the following format to provide for easy access for their clients and users:
-----------------------------------------------------------------------------------------
Particular | InvoiceNo | Date | Qty | Claimed | Assessed |
| | | |------------------------------------------------
| | | |Qty | Rate | Amount | Qty | Rate | Amount |
-----------------------------------------------------------------------------------------
|100 | 8 | 800 | 100 | 8 | 800
Apple | I-90 |2-12-2014 |1000 |500 | 8 | 4000 | 500 | 8 | 4000
-----------------------------------------------------------------------------------------
Total : 1000 | 600 4800 | 600 | 4800
Here I want to show total Sum of Qty (total ) i.e. 1000 Kg , Claimed Qty : 600
ClaimedAmount : 4800 .. Assessed Qty : 600 .. Assessed Amount : 4800
There might be assessed quantity which can be edited by the owner, and amount and rate may also vary, but the main and important thing is how to show a row against multiple columns of Claimed And Assessed Description.
Code behind Sql Storage is as follows:
ALTER PROCEDURE [dbo].[InsertTable] #claimID VARCHAR(25) = ''
,#Updateby VARCHAR(70) = ''
,#AffectedQty VARCHAR(30) = ''
,#myTableType MyTableType1 readonly
,#myInvoiceTable MyInvoiceTableNew readonly
AS
-- here MyTableType1 and MyInvoiceTableNew are user defined data types
BEGIN
BEGIN TRY
BEGIN TRANSACTION
DELETE
FROM InvoiceDetail
WHERE Claim_ID = #claimID
INSERT INTO InvoiceDetail (
Claim_ID
,Currency
,Particulars
,InvoiceNo
,InvoiceDate
,Invoice_Qty
,UOM
,Rate
,Amount
,UpdateBy
,UpdateDate
,STATUS
)
SELECT #claimID
,Currency
,Particulars
,InvoiceNo
,InvoiceDate
,Invoice_Qty
,UOM
,Rate
,Amount
,#Updateby
,convert(DATETIME, GETDATE(), 103)
,1
FROM #myInvoiceTable
DELETE
FROM Invoice_Damage_Detail
WHERE Claim_ID = #claimID
INSERT INTO Invoice_Damage_Detail (
Claim_ID
,Particulars
,InvoiceNo
,Invoice_Qty
,Affected_Qty
,UOM
,Rate
,Remarks
,UpdateBy
,UpdateDate
,STATUS
)
SELECT #claimID
,Particulars
,InvoiceNo
,Invoice_Qty
,Affected_Qty
,UOM
,Rate
,Remarks
,#Updateby
,convert(DATETIME, GETDATE(), 103)
,1
FROM #myTableType
DELETE
FROM Invoice_Final_Assessment_Details
WHERE ClaimID = #claimID
INSERT INTO Invoice_Final_Assessment_Details (
ClaimID
,Particular
,InvoiceNo
,InvoiceDate
,InvoiceQty
,ClaimedQty
,ClaimedRate
,ClaimedAmount
,ClaimedUOM
,AssessedQty
,AssessedRate
,AssessesAmount
,Createdate
,UpdateDate
,UpdatedBy
,IsDeleted
)
SELECT #claimID
,mt2.Particulars
,mt2.InvoiceNo
,mt2.InvoiceDate
,mt2.Invoice_Qty
,mt.Affected_Qty
,mt2.Rate
,(CONVERT(BIGINT, isnull(mt2.Invoice_Qty, 0)) * Convert(BIGINT, isnull(mt.Rate, 0))) AS ClaimedAmount
,mt2.UOM
,mt.Affected_Qty
,mt.Rate
,(CONVERT(BIGINT, isnull(mt.Affected_Qty, 0)) * Convert(BIGINT, isnull(mt.Rate, 0))) AS ClaimedAmount
,GETDATE()
,GETDATE()
,#Updateby
,0
FROM #myTableType mt
JOIN #myInvoiceTable mt2 ON 1 = 1
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
END CATCH
END
And now which join 1=1 i am applying in Database it repeats the number of line and invoice quantity and all amount gets doubled And USELESS.
I have a sqlite database with some time series data:
holdings:
| id | date | instrument | position | price | portfolio | sector |
prices:
| id | date | instrument | open | high | low | close | adjclose |
static_data
| id | ticker | name | sector | industry | country | currency |
and I'd like to get the holdings for a particular day with the change in price on that day as a calculated field.
I've tried the following query
SELECT h.date,
h.portfolio,
h.instrument,
s.name,
h.position,
p.adjclose AS curpx,
(p.adjclose AS lastpx WHERE
h.date = "2013-01-10 00:00:00" AND
h.instrument = p.instrument)
FROM holdings AS h,
static_data AS s,
prices AS p
WHERE h.date = "2013-01-11 00:00:00"
AND h.portfolio = "usequity"
AND (h.instrument = p.instrument)
AND (h.date = p.date)
AND (h.instrument = s.ticker);
but I get a syntax error.
[2014-11-14 06:11:04] [1] [SQLITE_ERROR] SQL error or missing database (near "as": syntax error)
I'm a complete N00b at SQL so I'd like to know how I can get two sets of data from the same table and show them side by side or to perform a calculation using one against the other in SQL.
Thanks
You want a correlated subquery:
SELECT ...,
p.adjclose AS curpx,
(SELECT p2.adjclose
FROM prices AS p2
WHERE p2.date = datetime(h.date, '-1 days')
AND p2.instrument = h.instrument
) AS lastpx
FROM ...
So I'm making a movie website and in my database table, I've got a column called Genre. In this I have listed the genres like this; Horror, Action.
Example Table
+----+---------+--------+
| id | Genre |
+----+---------+--------+
| 1 | Action |
| 2 | Horror, Action |
| 3 | Horror |
| 4 | Action |
| 5 | Romance, Drama |
| 6 | Horror, Drama |
+----+---------+--------+
So if I were to do a query to get films with a Horror genre, it would return the ID's 2,3 & 6. How would I go about structuring a query to do this?
Thanks.
The structure of your database is no good. Read up on database normalization to understand why this is. I would go with a structure like this:
Movie:
Id
Name
Movie_Genres
Movie_Id
Genre_Id
Genres:
Id
Name
You can then do a query like this:
SELECT m.name
FROM Movie as m
INNER JOIN Movie_Genres as mg
ON mg.Movie_id = m.id
WHERE mg.Genre_id = {Horror genre Id}
If you don't structure your DB like this you will run into a lot of problems down the road.
Continuing off of #Abe's excellent answer. If you want to build a comma delimited string based on #Abe's normalized 3 table structure it would look like this:
SELECT m.Name,
STUFF(( SELECT ', ' + g.Name
FROM Movie_Genres as mg
INNER JOIN Genres AS g on mg.Genre_id = g.Id and mg.Movie_id = m.id
FOR XML PATH('')
), 1, 2, '')
FROM Movie AS m
GROUP BY m.Name, m.Id;
Here's a Fiddle
I have table [Surgery_By] table[Surgery] table[Doctor] i'm using ASP.NET with SQL Server :
The table [Surgery_By] contains the following columns:
1-ID (PK)
2-Surgery ID (FK)
3-Doctor ID (FK)
How to Display doctors ordered by number of performed surgeries ?
Try it this way
SELECT d.id, d.fullname, COUNT(s.id) total_surgeries
FROM doctor d LEFT JOIN surgery_by s
ON d.id = s.doctor_id
GROUP BY d.id, d.fullname
ORDER BY total_surgeries DESC
Sample output:
| ID | FULLNAME | TOTAL_SURGERIES |
|----|------------|-----------------|
| 1 | John Doe | 3 |
| 2 | Jane Doe | 1 |
| 3 | Mark Smith | 0 |
Here is SQLFiddle demo
This is a stab in the dark.
Select Doctor.ID As DoctorID
,Count(*) As Count
From Doctor
Join Surgery_By
On Doctor.ID = Surgery_By.DoctorID
Group By Doctor.DoctorID
Order By Count(*)
I am not sure if you want the table Surgery incorporated (but if you do, the join will be pretty straight forward - just be sure to add selected columns to the Group By statement.)
From ASP.NET, you may select this data from a SQL Command.