In our MicroStrategy 9.3 environment, we have a star schema that has multiple date dimensions. For this example, assume we have a order_fact table has two dates, order_date and ship_date and an invoice_fact table with two dates invoice_date and actual_ship_date. We have a date dimension that has "calendar" related data. We have setup each date with an alias, per the MicroStrategy Advanced Data Warehousing guide, which is MicroStrategy's recommended approach to handling role-playing dimensions.
Now for the problem. The aliased dates allow for users to create reports specific to the date that has been aliased. However, since the dates have been aliased, MicroStrategy won't combine "dates" as they appear to it to be different. Case in point, I can't easily put on a report that shows order quantities and invoice quantities by order_date and invoice_date as it results in a cross join.
The solution we have been talking about internally, is creating a new attribute called order_fact_date and an invoice_fact_date. These dates would be determined at runtime via the psuedo code below:
case when <user picked date> = 'order date'
then order_date
else ship_date end as order_fact_date
case when <user picked date> = 'invoice date'
then invoice_date
else actual_ship_date as invoice_fact_date
Our thinking was then, we could have a "general" date dimension mapped to both dates which would enable MicroStrategy to leverage the same table in the joins and thereby eliminating the cross join issue.
Clear as mud?
Edit 1: Changed "three dates" to "two dates".
if I have understood correctly your problem, you have created multiple dates attributes (with different logical meaning) and they are mapped on different aliases of the calendar table.
Until users use different a single fact table in their reports there is no problem, but when they use metrics/facts from sales and invoices you have multiplied results because "Order Date" and "Invoice Date" are different attributes.
Your SQL looks something like:
...
FROM order_fact a11
INNER JOIN invoice_fact a12
INNER JOIN lu_calendar a13
ON a11.order_date = a13.date_id
INNER JOIN lu_calendar a14
ON a12.invoice_date = a14.date_id
...
As usual there are possible solution, not all of them very straight forward.
Option 1 - Single date attribute
You mention this possibility in your question, instead of using "Order Date" and "Invoice Date", just use a single "Date" attribute and teach users to use it. You can call it "Reporting Date" or "Operation Date" if this makes the life easier for them.
The SQL you should get is something like:
...
FROM order_fact a11
INNER JOIN invoice_fact a12
ON a11.order_date = a12.invoice_date
INNER JOIN lu_calendar a13 -- Only one join
ON a11.order_date = a13.date_id -- because the date is the same
...
Option 2 - We need to keep the two date attributes!
Map "Order Date" and "Invoice Date" on the same alias of your calendar table. This is usually can cause problems in MicroStrategy, because two attributes will be joined together on the same look-up table [see later on this], but in your case this is exactly what you are looking for.
With this solution you should get an SQL like this:
...
FROM order_fact a11
INNER JOIN invoice_fact a12 -- Hey! this is again a cross join!
INNER JOIN lu_calendar a13
ON a11.order_date = a13.date_id -- Relax man, we got you covered.
AND a12.invoice_date = a13.date_id -- Yes, we do it!
...
This is nice, but it works only if you have description forms coming from the calendar table (this is not always the case with dates because the ID is usually also the actual value that you show on your reports). In case you don't have a join with the calendar lookup, you SQL will end up again with duplicated result:
...
FROM order_fact a11 -- Notice no join column between the two facts
INNER JOIN invoice_fact a12 -- and no other conditions will help to join them
...
For this reason if you want to keep the two attributes separate, beside mapping them on the same lookup, you should also:
Create an hidden attribute (let's call it "Date_on_fact") map it on the fact table and the calendar table and make it child of both "Order Date" and "Invoice Date".
Un-map the "Order Date" and "Invoice Date" from the fact tables.
The idea here is to force MicroStrategy to use always the SQL code always the calendar lookup table:
...
FROM order_fact a11
INNER JOIN invoice_fact a12 -- This is like the previous one
INNER JOIN lu_calendar a13 -- But I'm back to help you
ON a11.order_date = a13.date_id
AND a12.invoice_date = a13.date_id
...
The attribute "Date_on_fact" can actually be hidden and users don't need to put it in their reports, but MicroStrategy will use it to go from the parent attributes to the fact table.
Hope this can help you to get out from the mud.
We had a same problem.
We had to create a generic time hierarchy for this and connected 2 different invoice and order time hierarchies to the generic one.
It works like charm!
Related
I'm a new in SAP B1.
Have a task to show the Sales and Returns for the period by BP in one query and after to create the Crystal Report based on data.
ORDR and RDR1 - Sales
ORDN and RDN1 - Returns.
Can you please advise how can I join them?
Thanks in advance.
To receive data from both business objects (orders and returns) you should think about UNIONing them instead of JOINing.
A pure SQL query (HANA flavor in this example) would look like this:
SELECT
"CardCode"
,"ItemCode"
,SUM("Total Sale") AS "Total Sale"
,SUM("Total Return") AS "Total Return"
FROM
(
SELECT
ORDR."CardCode"
,RDR1."ItemCode"
,RDR1."Quantity" AS "Total Sale"
,0 AS "Total Return"
FROM ORDR
JOIN RDR1
ON ORDR."DocEntry" = RDR1."DocEntry"
WHERE ORDR."DocDate" BETWEEN '2020-01-01' AND '2020-06-30'
UNION ALL
SELECT
ORDN."CardCode"
,RDN1."ItemCode"
,0 AS "Total Sale"
,RDN1."Quantity" AS "Total Return"
FROM ORDN
JOIN RDN1
ON ORDN."DocEntry" = RDN1."DocEntry"
WHERE ORDN."DocDate" BETWEEN '2020-01-01' AND '2020-06-30'
)
GROUP BY
"CardCode"
,"ItemCode"
To get the results into Crystal Reports (CR) there are quite some options. You may try to
create a database view from the query shown above and query that view from CR
or create a database view from the inner query above (i.e. the one in round brackets), query that from CR, and do the grouping in CR
or use CR's "Command" as data source, and build the command like you would create a database view.
List item
I am kinda new in PostgreSQL and I have difficulty to get the result that I want.
In order to get the appropriate result, I need to make multiple joins and I have difficulty when counting grouping them in one query as well.
The table names as following: pers_person, pers_position, and acc_transaction.
What I want to accomplish is;
To see who was absent on which date comparing pers_person with acc_transaction for any record, if there any record its fine... but if record is null the person was definitely absent.
I want to count the absence by pers_person, how many times in month this person is absent.
Also the person hired_date should be considered, the person might be hired in November in October report this person should be filtered out.
pers_postition table is for giving position information of that person.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
SELECT tr.create_time::date AS Date, pers.pin, tr.dept_name, tr.name, tr.last_name, pos.name, Count(*)
FROM acc_transaction AS tr
RIGHT JOIN pers_person as pers
ON tr.pin = pers.pin
LEFT JOIN pers_position as pos
ON pers.position_id=pos.id
WHERE tr.event_no = 0 AND DATE_PART('month', DATE)=10 AND DATE_PART('month', pr.hire_date::date)<=10 AND pr.pin IS DISTINCT FROM tr.pin
GROUP BY DATE
ORDER BY DATE
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
*This is report for octeber,
*Pin is ID number
I'd start by
changing the RIGHT JOIN for a LEFT JOIN as they works the same in reverse but it's confusing to figure them both in mind :
removing for now the pers_position table as it is used for added information purpose rather than changing any returned result
there is an unknown alias pr and I'd assume it is meant for pers (?), changing it accordingly
that leads to strange WHERE conditions, removing them
"pers.pin IS DISTINCT FROM pers.pin" (a field is never distinct from itself)
"AND DATE_PART('month', DATE)=10 " (always true when run in october, always false otherwise)
Giving the resulting query :
SELECT tr.create_time::date AS Date, pers.pin, tr.dept_name, tr.name, tr.last_name, Count(*)
FROM pers_person as pers
LEFT JOIN acc_transaction AS tr ON tr.pin = pers.pin
WHERE tr.event_no = 0
AND DATE_PART('month', pers.hire_date::date)<=10
GROUP BY DATE
ORDER BY DATE
At the end, I don't know if that answers the question, since the title says "Compare 2 Tables When 1 Is Null in PostgreSQL" and the content of the question says nothing about it.
I have 2 tables as below.
BILLING
AccountId RatingDate Load
1280582 2018-01-04 15:20:13.000 130.000
421947 2018-01-04 11:44:58.000 176.000
1033717 2018-01-04 10:52:23.000 234.000
RATING
AccountId RatingDate RatingMethod
1280582 2018-01-04 15:20:13.000 A
421947 2018-01-04 11:44:58.000 A
1033717 2018-01-04 10:52:23.000 A
I need to create a measure in Billing table to calculate the sum of Load column. I have the SQL query to perform the same but I am not able to create the measure with the same logic.
SELECT SUM(b.Load)
FROM Billing b
LEFT JOIN Rating r
ON b.AccountId = r.AccountId
AND b.RatingDate = r.RatingDate
WHERE r.RatingMethod = 'A'
Can someone help me with the dax formula for creating the measure?
There are a few ways to approach this including
Do the left join in the query editor.
Create bridge tables or unique indexing columns to relate your two tables.
Write a measure using the LOOKUPVALUE function.
If you're doing a bunch of other stuff, you'll probably want to consider option #1 or #2, but for just this particular measure, I'll show you #3.
LoadSum = CALCULATE(SUM(Billing[Load]),
FILTER(Billing,
LOOKUPVALUE(Rating[RatingMethod],
Rating[AccountID], Billing[AccountID],
Rating[RatingDate], Billing[RatingDate])
= "A"))
The above sums over the [Load] after filtering rows where [RatingMethod] = "A" in the Rating table (and matching on the ID and date columns).
For #1, select your Rating query and click Merge Queries (Home tab).
Select the columns you want to join one (Ctrl+Click in the same order on both of them). Keep the default Left Outer Join and hit OK.
Once they're merged, you'll have a new column named Billing. Click the expand icon in the top right corner of the column and select which columns you want to expand (select Load only).
Once expanded, your table should look like this:
RATING
AccountId RatingDate RatingMethod Load
1280582 2018-01-04 15:20:13 A 130
421947 2018-01-04 11:44:58 A 176
1033717 2018-01-04 10:52:23 A 234
I tried using dataset. But how can I give one dataset queries output as input to another dataset.
For example, balancesheet type report view.
My first query is
SELECT column_name_one FROM table WHERE C_GL_PRIMARY='LIABILITY'
Suppose this query returns me 2 rows, like DEPOSIT,LOAN.
My second query is
SELECT colum_name_second FROM table WHERE C_GL_ONE='column_name_one'
(i did it using datagrid and is working)
for example
DEPOSIT
term deposit
pigmy deposit
LOANS
term loan
pigmy loan
Till here everything is fine but now i have one more query which need output of second query as input for this query.
select column_name_third from table where C_GL_TWO='colum_name_second'
Here i am not able to put "colum_name_second" as input becoz it this fiels is under list not in details..
My report should look like this
DEPOSIT
term deposit
new term deposit
old term deposit
pigmy deposit
ww pigmy deposit
bbb deposit
LOANS
term loan
new tem loan
current term loan
pigmy loan
pigmyloannew
Can anybody help me ...Is there any way to do it.
Thanks.
1ST-Create the Parameter in Main report query and enter the parameter value in HashMap to populate it.
2nd-Create the parameter in dataset and use the parameter in dataset query.$p{Dataset_parameter}
3rd-If you are using List component right click on then go Edit list data source then click parameter then add the parameter of dataset and configure it with Main query output attribute.
Ex-select ID,NAME from CALENDAR WHERE REGION=$P{REGION_ID}--REGION_ID main report parameter
SELECT HOLIDAY_NAME,DATE_PICKER FROM HOLIDAYS WHERE CAL_ID=$P{CAL_ID} --CAL_ID dataset
parameter.configure as per instruction above with $P{CAL_ID} with expression $F{ID}
From your description this should just be a single query:
SELECT t1.column_name_one, t2.column_name_two, t3.column_name_three
FROM table1 t1
INNER JOIN table2 t2 on (t2.C_GL_ONE = t1.column_name_one)
INNER JOIN table3 t3 on (t3.C_GL_TWO = t2.column_name_two)
WHERE t1.C_GL_PRIMARY='LIABILITY'
Then the report would be grouped to show the data exactly as in your desired report output.
I am trying to CROSS JOIN two tables, customers and items, so I can then create a sales by customer by item report. I have 2000 customer and 2000 items.
SELECT customer_name FROM customers; --Takes 100ms
SELECT item_number FROM items; --Takes 50ms
SELECT customer_name, item_number FROM customers CROSS JOIN items; Takes 200000ms
I know this is 4 million rows, but is it possible to get this to run any faster? I want to eventually join this with a sales table like this:
SELECT customer_name, item_number, sales_total FROM customers CROSS JOIN items LEFT JOIN sales ON (customer.customer_name = sales.customer_name, item.item_number=sales.item_number);
The sales table will obviously not have all customers or all items, so the goal here is to have a report that shows all customers and all items along with what was sold and not sold.
I'm using PostgreSQL 8.4
To answer your question: No, you can't do a cross join faster than that - if you could then that would be how CROSS JOIN would be implemented.
But really you don't want a cross join. You probably want two separate queries, one which lists all customers, and another which lists all items and whether or not they were sold.
This really needs to be multiple reports. I can think of several off the top of my head that will yield more efficient packaging of information:
Report: count of all purchases by customer/item (obvious).
Report: list of all items not purchased, by customer.
Report: Summary of Report #2 (count of items) in order to prioritize which customers to focus on.
Report: list of all customer that have not bought an item by item.
Report: Summary of Report #3 (count of customers) in order to identify both the most popular and unpopular items for further action.
Report: List of all customers who purchased an item in the past, but did not purchase it his reporting period. This report is only relevant when the sales table has a date and the customers are expected to be regular buyers (i.e. disposable widgets). Won't work as well for things like service contracts.
The point here is that one should not insist that the tool process every possible outcome at once and generate more data and anyone could possibly digest manually. One should engage the end-users and consumers of the data as to what their needs are and tailor the output to meet those needs. It will make both sides' lives much easier in the long run.
If you wish to see all items for a given client (even if the cient has no items), i would rather try
SELECT c.customer_name, i.item_number, s.sales_total
FROM customers c LEFT JOIN
sales s ON c.customer_name = s.customer_name LEFT OIN
items i on i.item_number=s.item_number
This should give you a list of all clients, and all items joined by sales.
Perhaps you want something like this?
select c.customer_name, i.item_number, count( s.customer_name ) as total_sales
from customers c full join sales s on s.customer_name = c.customer_name
full join items i on i.item_number = s.item_number
group by c.customer_name, i.item_number