I'm sadly out of ideas. I'm currently learning in COGNOS analytics and I could use your help.
I have crosstable that looks like this and comes from different system that uses the same source structure. I use company account and am a user, so I cannnot sadly write SQL or any scripts!
MIS0 MIS1 MIS3 MIS6
2016 0,0 0,1 0,3 0,6
2017 0,0 0,1 0,4 0,7
2018 0,0 0,2 0,4 0,7
I replicated this in COGNOS but cannot get one thing right (it's much more difficult than than but I think that this is the core)
explanation:
MIS = months in service
years = year of product manufactury
values = (faults / manufactured (that year) and sold products) * 1000
Fault has property MIS = which MIS it happened in, also product has property something like dateOfManufacture
ok so the problem... to have e.g. MIS6 means: Fault that happened within 6 months since purchase. The complication starts that MIS3 fault logically belongs to MIS6 fault too.
So I need to create data-element or filter or some other trick that would enable me to:
select faults relevant for MIS from 0 to X where X will be the number in the header for columns (0,1,3,6...) based of course on year of manufacture .. I'm limited by my user rights so please if you have a suggestion that contains writing a script, thank you, you roll! :) but I won't be able to do it via script.
Excuse the lack of details but named variables or any code is a part of the confidetiality I'm bound by. :(
Thank you for the time and have a nice weekend!
Fault
MIS: 2
ProductID: <121212>
Product
ProductID: <121212>
Date of assembly: 25.02.2020
(MIS: gets copied to product fault when fault occours)
Table is supposed to view faults that have happened in specific months in service - that means that if fault is as above example says in 2 months in service, it should be calculated into columns MIS3 and MIS6 and not calculated into MIS1 and MIS0 statistics since the fault didn't occour in 1 months but in 2.
Basically e.g. the first row second column says: find me products that have been manufactured in 2016 - count how many faults they had in first month in service. This number divide by the number of products you found (first sentence) and all this multiply by 1000 (faults/1000)
As you can now probably see the problem occours when you move to next column on the same row. -> find me products that have been manufactured in 2016. Count how many fault they had in 3 months of service (= 1,2,3 included) and then divide by the number of products made - multiply by 1000.
When I set up crosstab I need to use inteval (MIS0 - MIS1,3,6) with floating maximum, but I don't have the brain to make it..
Try with a list first. If this works, we can convert the list to a crosstab
Let's start by isolating the metric in context to time
This would be your first column
For one month. Create a data item [Month 1 Faults] like this:
if ([Year] = 2016 and [Month] = 1)Then([Faults])Else(0)
Next column is for both month 1 and 2. We add the function IN(1,2) to accomplish this
Create a data item [Month 1 & 2 Faults] like this:
if ([Year] = 2016 and [Month] IN(1,2))Then([Faults])Else(0)
repeat this logic for all of the other data items
Related
Background
I have a database that hold records of all assets in an office. Each asset have a condition, a category name and an age.
A ConditionID can be;
In use
Spare
In Circulation
CategoryID are;
Phone
PC
Laptop
and Age is just a field called AquiredDate which holds records like;
2009-04-24 15:07:51.257
Example
I've created an example of the inputs of the query to explain better what I need if possible.
NB.
Inputs are in Orange in the above example.
I've split the example into two separate queries.
Count would be the output
Question
Is this type of query and result set possible using SQL alone? And if so where do I start? Would it be easier to use Ms Excel also?
Yes it is possible, for your orange fields you can just e.g.
where CategoryID ='Phone' and ConditionID in ('In use', 'In Circulation')
For the yellow one you could do a datediff of days of accuired date to now and divide it by 365 and floor that value, to get the last one (6+ years category) you need to take the minimum of 5 and the calculated value so you get 0 for all between 0-1 year old etc. until 5 which has everything above 6 years.
When you group by that calculated column and select the additional the count you get what you desire.
I want something strange here. I've table names as EMP_INFO which contains few details of an employee (i.e. Name,Designation, JOIN_FROM, JOIN_TO). I am trying to figure out term for each employee on yearly basis. I've below types of data
EMP_ID EMP_DESIG JOIN_FROM JOIN_TO Query Result
1 Supervisor 01-05-11 30-04-13 Should Display
2 Supervisor 15-06-10 31-12-12 Should Display
3 Jobar 01-01-12 31-12-13 Should Display
4 SR Superior 01-12-11 31-12-15 Should Display
5 Supervisor 01-05-11 31-12-13 Should Display
6 Supervisor 01-05-11 31-12-13 Should Display
7 Supervisor 01-05-11 31-12-13 Should Display
8 Supervisor 01-02-12 15-06-13 Should Display
9 SR Superior 16-03-10 18-11-11 Should Display
10 SR Superior 16-06-05 18-11-11 Should Display
11 Jobar 30-11-11 31-12-13 Should Display
12 Superior 02-02-05 31-12-20 Should Display
13 Jobar 30-11-11 31-12-13 Should Display
14 Jobar 30-11-09 31-12-10 Should Not Display
Basically what i need is I have date range in my report and let's say From: "01-Jun-11" To "31-Dec-13". From above record set report should retrieve all records as all records contains this both dates.
I have tried by using BETWEEN syntax but i believe it will not work.
If anyone can help me in this than it would be appreciated.
Thanks in Advance.. And one more thing if this details is not enough to understand than let me know i will add more in details.
Modified
Query which I tried
SELECT EI.*
FROM EMP_INFO EI,
(SELECT
TO_DATE('01-JUN-2011','DD-MON-YYYY') A,
TO_DATE('31-DEC-2013','DD-MON-YYYY') B FROM DUAL) X
WHERE
(EI.JOIN_FROM IS NOT NULL AND EI.JOIN_TO IS NOT NULL)
AND (
X.A BETWEEN EI.JOIN_FROM AND EI.JOIN_TO
AND X.B BETWEEN EI.JOIN_FROM AND EI.JOIN_TO
OR (EI.JOIN_FROM >= X.B AND EI.JOIN_TO <=X.A) )
Modified Added column (Query Result) on above table which contains result for each record.
So you simply want all records where the join time is in the given time range? That would be:
SELECT *
FROM EMP_INFO
WHERE JOIN_FROM BETWEEN
TO_DATE('01-JUN-2011','DD-MON-YYYY', 'NLS_DATE_LANGUAGE=AMERICAN') AND
TO_DATE('31-DEC-2013','DD-MON-YYYY', 'NLS_DATE_LANGUAGE=AMERICAN')
AND JOIN_TO BETWEEN
TO_DATE('01-JUN-2011','DD-MON-YYYY', 'NLS_DATE_LANGUAGE=AMERICAN') AND
TO_DATE('31-DEC-2013','DD-MON-YYYY', 'NLS_DATE_LANGUAGE=AMERICAN');
EDIT: Sorry, I got it now. You are looking for all time ranges that overlap with the given range. That would be: ranges that start before and end within, ranges that start before and end after, ranges that start within and end within and ranges that start within and end after. Another way to express this is: Either the given time range start is within the other time range or the other time range start is within the given time range. Here is the according statement:
SELECT *
FROM EMP_INFO
WHERE JOIN_FROM BETWEEN
TO_DATE('01-JUN-2011','DD-MON-YYYY', 'NLS_DATE_LANGUAGE=AMERICAN') AND
TO_DATE('31-DEC-2013','DD-MON-YYYY', 'NLS_DATE_LANGUAGE=AMERICAN')
OR TO_DATE('01-JUN-2011','DD-MON-YYYY', 'NLS_DATE_LANGUAGE=AMERICAN')
BETWEEN JOIN_FROM AND JOIN_TO;
And here is the SQL fiddle: http://sqlfiddle.com/#!4/b58b3/3
Convert to same format and compare. There may be a time component in the dates stored in database. Previous answer was wrong.
This question already has answers here:
Trying to find vehicles which are free between 2 variable dates
(2 answers)
Closed 8 years ago.
So I am kind of stuck on this Query I need to do, I have no Idea what It even means.
I need to be able to find a vehicle number from a table entitled Vehicle_Details and check whether it is currently in use for the period Of time I would like to use it as said bellow.
When a new trip is being arranged, the administrator has to find a vehicle that is not already in use for the trip duration. Because this query will be needed frequently, it is important that it can be run easily for an arbitrary start and end date. It should therefore use substitution variables so that the trip start and end dates can be provided at run time.
Make sure that when it is run the user is only prompted to supply the start and end dates once. Also make sure that any vehicles displayed are available for the entire period specified - you will have to include more than one test in the where clause
Any code would be helpful but even links to things that can help me write it myself as I have No idea tbh.
Example data from the three tables:
Trip_ID Departure Return_Date Duration Registration
73180 07-FEB-12 08-FEB-12 1 PY09 XRH
73181 07-FEB-12 08-FEB-12 1 PY10 OPM
73182 07-FEB-12 10-FEB-12 3 PY56 BZT
73183 07-FEB-12 08-FEB-12 1 PY56 BZU
73184 07-FEB-12 09-FEB-12 2 PY58 UHF
Registration Make Model Year
4585 AW ALBION RIEVER 1963
SDU 567M ATKINSON N/A 1974
P525 CAO DAF FT85.400 1996
PY55 CGO DAF FTGCF85.430 2005
PY06 BYP DAF FTGCF85.430 2006
Weight Registration Body Vehicle ID
20321 4585 AW N/A 1
32520 SDU 567M N/A 2
40000 P525 CAO N/A 3
40000 PY55 CGO N/A 4
40000 PY06 BYP N/A 5
You need to find if a particular date range intersects with any reservation. This is interval intersection arithmetic. Consider the following intervals [A,B] and [x,y]:
-----------[xxxxxxxxxxx]-------------
A B
---------------------[xxxxxx]--------
x y
An interval [x,y] will intersect with [A,B] if and only if:
B >= x
And A <= y
So your query will look like:
SELECT *
FROM registrations reg
WHERE reg.registration = :searched_vehicle
AND NOT EXISTS (SELECT NULL
FROM reservations res
WHERE res.registration = reg.registration
AND res.return_date >= :interval_start
AND res.departure <= :interval_end)
This is for one vehicle. If the query returns a row, this vehicle is available for the given interval [:interval_start, :interval_end].
I have a system where people can pick some stocks and it values their portfolios but I'm having trouble doing this in a efficient way on a daily basis because I'm creating entries for days that don't have any changes(think of it like I'm measuring the values and having version control so I can track changes to the way the portfolio is designed).
Here's a example(each day's portfolio with stock name and weight):
Day1:
ibm = 10%
microsoft = 50%
google = 40%
day5:
ibm = 20%
microsoft = 20%
google = 40%
cisco = 20%
I can measure the value of the portfolio on day1 and understand I need to measure it again on day5(when it changed) but how do I measure day2-4 without recreating day1's entry in the database?
My approach right now(which I don't like) is to create a temp entry in my database for when someone changes the portfolio and then at the end of the day when I calculate the values if there is a temp entry I use that otherwise I create a new entry(for day2-4) using the last days data. The issue is as data often doesn't change I'm creating entries that are basically duplicates. The catch is: my stock data is all daily. I also thought of taking the portfolio and if it hasn't been updated in 3 days to find the returns of the last 3 days for each stock but I wasn't sure if there was a better solution.
Any ideas? I think this is a straight forward problem but I just can't see a efficient way of doing it.
note: in finance terms, its called creating a NAV and most firms do it the inefficient way I'm doing it but its because the process was created like 50 years ago and hasn't changed. I think this problem is very similar to version control but I can't seem to make a solution.
In storage terms is makes most sense to just store:
UserId - StockId1 - 23% - 2012-06-25
UserId - StockId2 - 11% - 2012-06-26
UserId - StockId1 - 20% - 2012-06-30
So you see that stock 1 went down at 30th. Now if you want to know the StockId1 percentage at the 28th you just select:
SELECT *
FROM stocks
WHERE datecolumn<=DATE(2012-06-28)
ORDER BY datecolumn DESC LIMIT 0,1
If it gives nothing back you did not have it, otherwise you get the last position back.
BTW. if you need for example a graph of stock 1 you could left join against a table full of dates. Then you can fill in the gaps easily.
Found this post here for example:
UPDATE mytable
SET number = (#n := COALESCE(number, #n))
ORDER BY date;
SQL QUERY replace NULL value in a row with a value from the previous known value
The problem that I have is SQL Server Reporting Services does not like Sum(First()) notation. It will only allow either Sum() or First().
The Context
I am creating a reconciliation report. ie. what sock we had a the start of a period, what was ordered and what stock we had at the end.
Dataset returns something like
Type,Product,Customer,Stock at Start(SAS), Ordered Qty, Stock At End (SAE)
Export,1,1,100,5,90
Export,1,2,100,5,90
Domestic,2,1,200,10,150
Domestic,2,2,200,20,150
Domestic,2,3,200,30,150
I group by Type, then Product and list the customers that bought that product.
I want to display the total for SAS, Ordered Qty, and SAE but if I do a Sum on the SAS or SAE I get a value of 200 and 600 for Product 1 and 2 respectively when it should have been 100 and 200 respectively.
I thought that i could do a Sum(First()) But SSRS complains that I can not have an aggregate within an aggregate.
Ideally SSRS needs a Sum(Distinct())
Solutions So Far
1. Don't show the Stock at Start and Stock At End as part of the totals.
2. Write some code directly in the report to do the calc. tried this one - didn't work as I expected.
3. Write an assembly to do the calculation. (Have not tried this one)
Edit - Problem clarification
The problem stems from the fact that this is actually two reports merged into one (as I see it). A Production Report and a sales report.
The report tried to address these criteria
the market that we sold it to (export, domestic)
how much did we have in stock,
how much was produced,
how much was sold,
who did we sell it to,
how much do we have left over.
The complicating factor is the who did we sell it to. with out that, it would have been relativly easy. But including it means that the other top line figures (stock at start and stock at end) have nothing to do with the what is sold, other than the particular product.
I had a similar issue and ended up using ROW_NUMBER in my query to provide a integer for the row value and then using SUM(IIF(myRowNumber = 1, myValue, 0)).
I'll edit this when I get to work and provide more data, but thought this might be enough to get you started. I'm curious about Adolf's solution too.
Pooh! Where's my peg?!
Have you thought about using windowing/ranking functions in the SQL for this?
This allows you to aggregate data without losing detail
e.g. Imagine for a range of values, you want the Min and Max returning, but you also wish to return the initial data (no summary of data).
Group Value Min Max
A 3 2 9
A 7 2 9
A 9 2 9
A 2 2 9
B 5 5 7
B 7 5 7
C etc..
Syntax looks odd but its just
AggregateFunctionYouWant OVER (WhatYouWantItGroupedBy, WhatYouWantItOrderedBy) as AggVal
Windowing
Ranking
you're dataset is a little weird but i think i understand where you're going.
try making the dataset return in this order:
Type, Product, SAS, SAE, Customer, Ordered Qty
what i would do is create a report with a table control. i would set up the type, product, and customer as three separate groups. i would put the sas and sae data on the same group as the product, and the quantity on the customer group. this should resemble what i believe you are trying to go for. your sas and sae should be in a first()
Write a subquery.
Ideally SSRS needs a Sum(Distinct())
Re-write your query to do this correctly.
I suspect your problem is that you're written a query that gets you the wrong results, or you have poorly designed tables. Without knowing more about what you're trying to do, I can't tell you how to fix it, but it has a bad "smell".