It is important to apply calculations and business rules consistently across QlikView applications. We can store variables, connections etc. in an external file and apply them across various QVW.
Is there a standardized script for time/calendar dimension that has practically everything you need regarding time, and which could be used accross different QVWs without having to spend time to create it all over again when developing a new QVW.
I would like to have something that is robust, has everything I need and that I can include in every QVW.
You can check for the Rob Wunderlich's Qlikview Components, there is a standard Calendar function you can call.
You can also check on his website, there's a very good script I use each time I make a report. You can put the result of the script in a QVD and load it on every report you make.
So It will be something like this:
MasterCalendar:
Load
TempDate AS OrderDate,
week(TempDate) As Week,
Year(TempDate) As Year,
Month(TempDate) As Month,
Day(TempDate) As Day,
'Q' & ceil(month(TempDate) / 3) AS Quarter,
Week(weekstart(TempDate)) & '-' & WeekYear(TempDate) as WeekYear,
WeekDay(TempDate) as WeekDay
;
//=== Generate a temp table of dates ===
LOAD
date(mindate + IterNo()) AS TempDate
,maxdate // Used in InYearToDate() above, but not kept
WHILE mindate + IterNo() <= maxdate;
//=== Get min/max dates from Field ===/
LOAD
AddYears(today(), -6) as mindate, // The first date you want
Today() as maxdate
AUTOGENERATE 1;
STORE MasterCalendar INTO 'Calendar.qvd' (qvd);
DROP TABLE MasterCalendar;
Two options:
You can create a .qvw that generates a calendar .qvd that contains all of the date fields (say DayOfMonth, DayOfWeek, Month etc.) as well as a Date field, called say CalendarDate. Then in all of your .qvw you can Left Join your fact table against the data loaded from the .qvd through the CalendarDate field. For performance reasons I would not leave the calendar as a separate table, if I can help it.
Otherwise you can create a text file that contains the column definitions in a variable that you can use as macro. Something like
LET CalendarFields = '
Year($1) as DateYear,
Month($1) as DateMonthOfYear,
Week($1) as DateWeekOfYear,
Day($1) as DateDayOfMonth,
WeekDay($1) as DateDayOfWeek,
Date(MonthStart($1), ''YYYY MMM'') as DateMonthInYear,
Year(WeekStart($1)) & ''w'' & Num(Week($1), ''00'') as DateWeekInYear ';
You can load this file, say common.txt with $(Must_Include=common.txt); or $(Include=common.txt);
Then in your load statement for your fact table, you can use this macro like like:
Facts:
LOAD
*,
$(CalendarFields(FactDateField));
Related
I have a SQL query that creates a table, and every month 2 new columns will be added for that table related to the current month.
I have tried without success to set up a flat table (visual) in Qlik that will automatically expand every month to include these table. Is there a way to do this, and i so please point me in the right direction.
You can have a look at CrossTable prefix.
This prefix allows a wide table to be converted to a long table.
So if we have data like this:
After running the following script:
CrossTable:
CrossTable(Month, Sales)
LOAD Item,
[2022-10],
[2022-11],
[2022-12],
[2023-01],
[2023-02],
[2023-03],
[2023-04]
FROM
[C:\Users\User1\Documents\SO_75447715.xlsx]
(ooxml, embedded labels, table is Sheet1);
The final data will looks like below. As you can see there are only 3 columns. All xls month columns (after Item) are now collapsed under one field - Month and all the values are collapsed under Sales column.
Having the data in this format then allows creating "normal" charts with adding Month column as dimension and use sum(Sales) as an expression.
P.S. If you dont want to manage the new columns being added then the script can be:
CrossTable(Month, Sales)
LOAD
Item,
*
FROM
...
I'm using Bullhorn Canvas which runs on Cognos. I'm looking for the simplest way to have query filters based on a prompt with this dropdown:
THIS WEEK
LAST WEEK
THIS MONTH
LAST MONTH
THIS QUARTER
LAST QUARTER
YEAR TO DATE
The report requires many queries with date filters. As far as I can see, I have to write filters in each query that look like this:
[StartDate] between
(case ?Dates Dropdown?
when 'THISWEEK' then _add_days(current_date, -_day_of_week(current_date, 1) + 1)
when 'LASTWEEK' then _add_days(current_date, -_day_of_week(current_date, 1) - 6)
when 'THISMONTH' then _first_of_month(current_date)
end)
and
(case ?Dates Dropdown?
when 'THISWEEK' then _add_days(current_date, -_day_of_week(current_date,1) + 7)
when 'LASTWEEK' then _add_days(current_date, -_day_of_week(current_date,1))
when 'THISMONTH' then _last_of_month(current_date)
when 'LASTMONTH' then _last_of_month(_add_months(current_date, -1))
end)
This is actually shortened. The real filter will be even bigger than this.
As far as I can see, I have to repeat this monstrous filter in every query, and I'd like to avoid that. In other programming languages, I'd create two variables, for example Date1 and Date2. I'd calculate those variables once, based on the dropdown. Then each query would simply say [StartDate] between [Date1] and [Date2].
Is there a way to do this in Cognos?
As a suggestion, we can use the value prompt with static values to set the ranges and then use a join to have the query (or multiple queries) filter based on that range
Step 1 create a value prompt with static values like this:
Step 2 create a query that will have the data items for the ranges like this:
Each data item has the case statement like you gave above
For example, this would be for the data item FromRange
Step 3 navigate to where you can see all of your queries. From the insertable objects, using a join you will have your query follow the from and to range like this:
The join would look like this (note towards the bottom for the operator we use >= for FROM):
and this for the range (and the <= for the TO):
Remember in the Query from the join you just need to re-add the data items you want to show in your content
Evening everyone
I've currently got a simple recycle view adapter which is being populated by an SQL Lite database. The user can add information into the database from the app which then build a row inside of the recycle view. When you run the application it will display each row with its own date directly above it. I'm now looking to make the application look more professional by only displaying a single date above multiple records as a header.
So far I've built 2 custom designs, one which displays the header along with the row and the other which is just a standard row without a header built in. I also understand how to implement two layouts into a single adapter.
I've also incorporated a single row into my database which simply stores the date in a way in which I can order the database e.g. 20190101
Now my key question is when populating the adapter using the information from the SQL Lite database how can get it to check if the previous record has the same date. If the record has the same date then it doesn't need to show the custom row with header but if its a new date then it does?
Thank you
/////////////////////////////////////////////////////////////////////////////
Follow up question for Krokodilko, I've spent the last hour trying to work your implementation into my SQL Lite but still not being able to find the combination.
below the is the original code SQL Lite line I currently use to simply gain all the results.
Cursor cursor = sqLiteDatabase.rawQuery("SELECT * FROM " + Primary_Table + " " , null);
First you must define an order which will be used to determine which record is previous and which one is next. As I understand, you are simply using date column.
Then the query is simple - use LAG analytic function to pick a column value from previous row, here is a link to a simple demo (click "Run" button):
https://sqliteonline.com/#fiddle-5c323b7a7184cjmyjql6c9jh
DROP TABLE IF EXISTS d;
CREATE TABLE d(
d date
);
insert into d values ( '2012-01-22'),( '2012-01-22'),( '2015-01-22');
SELECT *,
lag( d ) OVER (order by d ) as prev_date,
CASE WHEN d = lag( d ) OVER (order by d )
THEN 'Previous row has the same date'
ELSE 'Previous row has different date'
END as Compare_status
FROM d
ORDER BY d;
In the above demo d column is used in OVER (order by d ) clause to determine the order of rows used by LAG function.
I have problem with data that I need to filter out to produce a report.
Basically every day we take a file and load it into the system but the file is cumulative file and is basically re imported with the same information plus the new data daily.
This loads into the Database into two tables, a header and detail table.
In the header table I have the key filed of No_, the date it was imported and the month and year the data is for (period) an example would be 'Apr2013'.
The detailed table holds all of the information from the import as you can imagine.
What I'm looking to do is to disregard all of the older data and only look at the most recent import for that month only.
Hopefully someone can help me, if you want me to post any example data or anything then please let me know and I'll add it in.
Thanks in advance!
Phil
If you cannot change your process to stop re-importing the same data over and over - especially if the data is exactly the same - you could try the following query:
WITH MostRecentData AS
(
SELECT MAX(dateImported) dateImported, month, year
FROM header
GROUP BY month, year
)
SELECT ...
FROM detail d
INNER JOIN header h ON h.[key] = d.[key]
INNER JOIN MostRecentData r ON h.month = r.month AND h.year = r.year
AND h.dateImported = r.dateImporter
This will pull out the latest rows (based on the date imported) for each month and year.
Honestly though I would try to change the import process if possible. It sounds like a lot of wasted space and subsequent processing to pull out the data you want.
I have three tables:
Employee(Id,name etc)
Appointment(Id,date,time,employee id, clientid etc)
Client(Id,name etc)
The Employee table has a 1 to many with the Appointment table as does the Client table.
However what I'm trying to achieve is to allow for the system to prevent duplicate or conflicting appointments but cant quite get my head around how to go about this. Would I need an additional table with say available time slots and some how link it all together? Or for example an employee availability table in addition?
Or could I achieve what I need with what I already have and just by manipulation of queries?
Many thanks
I think an appointments table is going to be necessary. It will allow you to include only available slots and also to analyse employees workload and availability. The table would include 15 minute slots for each day for each employee. You may wish to add a further table for holidays / sick days / generally unavailable for a chunk of time.
EDIT
I had envisioned something on the lines of:
Timeslots:
EmployeeID ) Primary key
TimeSlot )
JobID - Foreign key
Status ) And so forth
Notes )
"I want an early appointment with E1"
SELECT TimeSlots.EmployeeID, TimeSlots.TimeSlot, TimeSlots.JobID
FROM TimeSlots
WHERE TimeSlots.EmployeeID=1
AND TimeSlots.TimeSlot Between #2/9/2012 9:0:0# And #2/9/2012 11:30:0#
"I want an appointment at 9:00am"
SELECT TimeSlots.EmployeeID, TimeSlots.TimeSlot, TimeSlots.JobID
FROM TimeSlots
WHERE TimeSlots.TimeSlot Between #2/9/2012 9:0:0# And #2/9/2012 9:30:0#
To prevent collisions, the logic here is quite simple:
A collision occurs when:
RequestStartDate <= EndDate
and
RequestEndDate >= StartDate
The above is thus a rather simply query. If any collision occurs, the
above will return records and you simply don't allow the booking.
The above of course can EASY be extended for time, and even a particular room.
Eg:
RequestStartTime <= EndTime
and
RequestEndTime >= StartTime
And
RequestDate = BookingDate
And in fact in access since you can store a date + time column, then we are quite much back to the first example above (and as such a booking can span multiple days if you do this). And as noted, if this was for a particular room, then just add a room condition to the above.
Access 2010 does have table triggers and store procedures, but since you need a UI for the user, then code like this normally does the trick:
dim strWhere as string
dim dtRequeestStartDate as date
dim dtRequestEndDate as date
dtRequestStartDate = inputbox("Enter start Date")
dtRequestEndDate = inputbox("Enter end date")
strWhere="#" & format(dtRequestStartDate,"mm/dd/yyyy") & "# <= EndDate" & _
" and #" & format(dtRequestEndDate,"mm/dd/yyyy") & "# >= StartDate"
if dcount("*","tableBooking",strWhere) > 0 then
msgbox "sorry, you cant book
...bla bla bla....
The above is just an example, and I am sure you would build a nice form that
prompts the user for the booking dates.
So the above simple conditions above does return ANY collisions. And having written so many reservation systmes, I strongly recommend you do NOT create blank records ahead of time, but use the above correct logic and thus ONLY add records to the booking system and not have to write tons of code to create a bunch of blank records with time slots etc.
The above simply query will prevent collisions.