Generating range of months using multi-level hierarchies - iccube

I want to filter the months of [ComptaEcriture Date] by selecting only the months from [ComptaPlanId].[ComptaDateDebut] to [ComptaPlanId].[ComptaDateFin], but since
[ComptaDateDebut] and [ComptaDateFin] are not from the same level and bot are not from the same dimension as [ComptaEcriture Date].[ComptaEcriture Date].[Month], I don't know how to achieve that.
If I could generate a range of months that would be great. My dimensions are as follows:

Assuming you're testing that PlanId is no the All member, you can use isAll MDX+ function for this.
For the set, we will combine the Filter function with a Declared function, even though we could put it all the code in the filter. It looks as :
WITH
FUNCTION inRange(Value _date,Value _start, Value _end) AS _start <= _date AND _date <= _end
SET myDates as Filter( [Date].[Date].[Month] as t, inRange(t.current.key, DateTime(2015,6,1), DateTime(2017,1,1) ) )
SELECT
myDates on 0
FROM [Cube]
And using the compact and faster version :
SELECT
Filter( [Date].[Date].[Month] as t, DateTime(2015,6,1) <= t.current.key AND t.current.key <= DateTime(2017,1,1) ) on 0
FROM [Cube]
Using the members :
WITH
FUNCTION inRange(Value _date,Value _start, Value _end) AS _start <= _date AND _date <= _end
SET myDates as Filter( [Date].[Date].[Month] as t,
inRange(t.current.key, [ComptaDateDebut].currentmember.key, [ComptaDateFin].currentmember.key )
)
SELECT
myDates on 0
FROM [Cube]
You can use contextMember instead of currentMember that check also in the slicer (FILTER BY or subselect)

Related

Quicksight Countover with Conditional

I have a table with order information. It is broken down by OrderID, Item Name. How can I get the count of all orders with multiple x and y items. For example, how many orders have more than 1 dumplings and more than 1 water?
You can use the Countif function like:
countIf (
Revenue,
# Conditions
CalendarDay >= ${BasePeriodStartDate} AND
CalendarDay <= ${BasePeriodEndDate} AND
SourcingType <> 'Indirect'
)
Documentation

SQLITE Join on Date = Date + x

I am using the following insert query to create a comparison between two tables using the dates to join on.
INSERT INTO Comp_Table (Date, CKROne, CKRTwo, ChangeOne, ChangeTwo, State)
SELECT BaseTbl.Date, BaseTbl.CKR, CompTbl.CKR, BaseTbl.Change, CompTbl.Change,
CASE
WHEN BaseTbl.Change > 0 AND CompTbl.Change > 0 THEN 'positive'
WHEN BaseTbl.Change < 0 AND CompTbl.Change < 0 THEN 'positive'
ELSE 'inversely'
END AS 'Correlation'
FROM BaseTbl
JOIN CompTbl ON BaseTbl.Date = CompTbl.Date;
This works well. However, I would like to be able to join the tables with a lag. As in, the user can define if they want to do exact match on dates or if they want to use a date of one's occurrence plus a number and return the value from the latter date for comparison to the number to the former date. Pseudo code example:
User sets variable = 0 then
Join ComTbl On BaseTbl.Date = CompTbl.Date + 0;
User sets variable = 7 then
Join CompTbl On BaseTbl.Date = CompTbl.Date + 7;
(joins 2012-01-01 from BaseTbl to 2012-01-08 from CompTbl)
I tried to add days like you would in a Where clause ('+7 day'), but this didn't work. I also tried to using a Where clause with BaseTbl.Date = CompTbl.Date '+ 7 day' but that returned a 0 value also. How can this be accomplished in SQLite?
I think you can use the DATE() function to build the WHERE clause you want:
INSERT INTO ...
SELECT ...
FROM BaseTbl
INNER JOIN ComTbl
ON BaseTbl.Date = DATE(CompTbl.Date, '7 days')

using doctrine and querybuilder, between two date

I want to retrieve some data using queryBuilder, the condition is to use a datetime field on parent table and pass it to where condition, the child table have two date start and end, the whole condition is to select parent row depend on date between the two date in child table
the code is:
$qb->select('parent,child')
->from($this->class, 'parent')
->innerJoin('parent.childTable', 'child')
//other join
// and where
//CONDITION -> startdate <= $date AND enddate >= $date
$betweenDates = $qb->expr()->andX(
$qb->expr()->gt("child.dateStart", "parent.datetime"),
$qb->expr()->lt("child.dateEnd", "parent.datetime")
);
//CONDITION 4 -> enddate == NULL
$endDateNull = $qb->expr()->isNull( 'child.dateEnd');
$dates = $qb->expr()->orX($betweenDates, $endDateNull);
// take care of dateEnd if it's null
$qb->expr()->andX($dates);
the problem is the where condition not work and the select still give me childs not respect date condition
any help would be greatly appreciated.

Working with date ranges (Classic ASP and SQL)

I have to implement a solution where two date ranges can overlap each other. within the overlapped dates, I have to count how many days overlap each other. Once I know the overlapped days I can calculate a total figure based on the price that's attached per day.
A scenario would be that
A customer is booking a hotel
Customer booking dates - 17/02/2011 to 26/02/2011
Normal price (All year) - 01/01/2011 - 31/12/2011 (price per day :$30.00)
Special Offer 1 dates - 01/01/2011 to 19/02/2011 (price per day :$20.00)
Special Offer 2 dates - 17/02/2011 to 24/02/2011 (price per day :$10.00)
In the above scenario, the proposed algorithm should work out the cheapest offer that the date ranges overlap and work out the price for the booking. If there is no special offer available it uses the normal price.
So for the first two days the system should get the price from "special offer 1" as it's the cheapest available price. Next 5 days should be "Special offer 2 price" and for the next 2 days it'll be normal price.
I'd be grateful to see both SQL(using MS-SQL Server) or Code base answers to get the diffrenet views.
I hope the question is clear and looking foward to see the answers.
Many thanks in advance
Using the standard trick of using an auxiliary calendar table, it is simply a case of joins and grouping to get the best price each day:
SELECT C.dt, MIN(price) AS best_price
FROM Prices P
INNER JOIN Calendar C
ON C.dt >= P.price_start_date
AND C.dt < P.price_end_date
INNER JOIN CustomerBooking B
ON C.dt >= B.booking_start_date
AND C.dt < B.booking_end_date
GROUP
BY C.dt;
The same query as above, including sample data using CTEs:
WITH Prices (price_start_date, price_end_date, narrative, price)
AS
(
SELECT CAST(start_date AS Date), CAST(end_date AS Date), narrative, price
FROM (
VALUES ('2011-01-01T00:00:00', '2011-12-31T00:00:00', 'Normal price', 30),
('2011-01-01T00:00:00', '2011-02-21T00:00:00', 'Special Offer 1', 20),
('2011-02-19T00:00:00', '2011-02-24T00:00:00', 'Special Offer 2', 10)
) AS T (start_date, end_date, narrative, price)
),
CustomerBooking (booking_start_date, booking_end_date)
AS
(
SELECT CAST(start_date AS Date), CAST(end_date AS Date)
FROM (
VALUES ('2011-02-17T00:00:00', '2011-02-26T00:00:00')
) AS T (start_date, end_date)
)
SELECT C.dt, MIN(price) AS best_price
FROM Prices P
INNER JOIN Calendar C
ON C.dt >= P.price_start_date
AND C.dt < P.price_end_date
INNER JOIN CustomerBooking B
ON C.dt >= B.booking_start_date
AND C.dt < B.booking_end_date
GROUP
BY C.dt;
Let's supose that for each day you should apply lowest price.
create function price ( #fromDate date, #toDate date) returns money
as
begin
declare #iterator_day date
declare #total money
set #total = 0
set #iterator_day = #fromDate
WHILE #iterator_day < = #toDate
begin
select #total = #total + min( price )
from offers
where #iterator_day between offers.fromFay and offers.toDay
set #iterator_day = DATEADD (day , 1 , #iterator_day )
end
return #total
end
then you can call function in your query:
select
b.fromDay, b.toDay, dbo.price( b.fromDay, b.toDay )
from
booking b
I've only used ASP.net 4.0, but I can offer some SQL will give you the price for a given date:
SELECT ISNULL(MIN(PricePerDay), 0) AS MinPricePerDay
FROM Offers
WHERE (StartDate <= '18/2/11') AND (EndDate >= '18/2/11')
From your application you could build the query to be something like this:
SELECT ISNULL(MIN(PricePerDay), 0) AS MinPricePerDay
FROM Offers
WHERE (StartDate <= '17/2/11') AND (EndDate >= '17/2/11');
SELECT ISNULL(MIN(PricePerDay), 0) AS MinPricePerDay
FROM Offers
WHERE (StartDate <= '18/2/11') AND (EndDate >= '18/2/11');
SELECT ISNULL(MIN(PricePerDay), 0) AS MinPricePerDay
FROM Offers
WHERE (StartDate <= '19/2/11') AND (EndDate >= '19/2/11');
This would return a dataset of tables containing a single value for the minimum price for that date (in the same order as your query)
Sounds like a good job for a Stored Procedure...
Your problem here is that you're got multiple overlapping time periods. You either need to constrain the problem slightly, or remodel the data slightly. (To get desirable performance.)
Option 1 - Constraints
A data set of 'normal' prices - that never overlap with each other
A data set of 'special' prices - that also never overlap with each other
Every bookable date has a 'normal' price
Every bookable date has a 'special' price (EVEN if it's NULL to mean 'no special price')
The last constraint is the strangest one. But it's needed to make the simple join work. When comparing date ranges, it's alot easier to form the query if the two sets of ranges are gapless and have no overlaps inside them.
This means that you should now be able to work it out with just a few joins...
SELECT
CASE WHEN [sp].started > [np].started THEN [sp].started ELSE [np].started END AS [started]
CASE WHEN [sp].expired < [np].expired THEN [sp].expired ELSE [np].expired END AS [expired]
CASE WHEN [sp].price < [np].price THEN [sp].price ELSE [np].price END AS [price]
FROM
normal_prices AS [np]
LEFT JOIN
special_prices AS [sp]
ON [sp].started < [np].expired
AND [sp].expired > [np].started
AND [sp].started >= (SELECT ISNULL(MAX(started),0) FROM special_prices WHERE started <= [np].started)
-- The third condition is an optimisation for large data-sets.
WHERE
[np].started < #expired
AND [np].expired > #started
-- Note: Inclusive StartDates, Exlusive EndDate
-- For example, "all of Jan" would be "2011-01-01" to "2011-02-01"
Option 2 - Re-Model
This one is often the fastest in my experience; you increase the amount of space being used, and gain a simpler faster query...
Table Of Prices, stored by DAY rather than period...
- calendar_date
- price_code
- price
SELECT
calendar_date,
MIN(price)
FROM
prices
WHERE
calendar_date >= #started
AND calendar_date < #expired
Or, if you needed the price_code as well...
WITH
ordered_prices AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY calendar_date ORDER BY price ASC, price_code) AS price_rank,
*
FROM
prices
)
SELECT
calendar_date,
price_code,
price
FROM
ordered_prices
WHERE
calendar_date >= #started
AND calendar_date < #expired

Count distinct in MDX (convert from SQL query)

SELECT COUNT (DISTINCT S.PK_Submission)
FROM Fact_Submission FS, Submission S
WHERE
FS.FK_Submission = S.PK_Submission
AND FS.FK_Submission_Date >= 20100101
AND FS.FK_Submission_Date <= 20101231
I've tried this:
SELECT
{[Measures].[Fact Submission Count]} ON AXIS(0),
Distinct({[Submission].[PK Submission] }) ON AXIS(1)
FROM [Submission]
WHERE
([Date].[Calendar Year].[2010])
but the result is the same
any idea how to write this in MDX? I'm pretty new at this so still haven't figured it out.
This is correct answer:
WITH SET MySet AS
{[Measures].[Fact Submission Count]}
*
DISTINCT({ EXCEPT([Submission].[PK Submission].Members, [Submission].[PK Submission].[All]) })
MEMBER MEASURES.DistinctSubmissionCount AS
DISTINCTCOUNT(MySet)
SELECT {MEASURES.DistinctSubmissionCount} ON 0
FROM [Submission]
WHERE
([Date].[Calendar Year].[2010])
I have excluded "All" row because it's also being counted by COUNT function so I always had +1.

Resources