Within Crystal Reports, I'm using the following query (against an Oracle database) to generate data for a single field in a report:
SELECT SUM(e1.ENT_LOCAL_AMOUNT+e1.ENT_DISCRETIONARY_AMOUNT) AS "Entitlement"
FROM CLAIM_PERIODS cp1
JOIN ENTITLEMENTS e1
ON cp1.CPE_REFNO=e1.ENT_CPE_REFNO
WHERE e1.ENT_REFNO=(SELECT MAX(to_number(e2.ENT_REFNO))
FROM ENTITLEMENTS e2
WHERE e1.ENT_CPE_REFNO=e2.ENT_CPE_REFNO
AND (e2.ENT_START_DATE <= {?HB_As_At_Date}
AND e2.ENT_END_DATE > {?HB_As_At_Date})
AND e2.ENT_CREATED_DATE<={?HB_As_At_Date})
AND cp1.CPE_CPA_CPY_CODE='HB'
This works fine and returns a single integer value, based on the {?HB_As_At_Date} supplied (The {?} syntax is Crystal's way of embedding parameter values into SQL). The content of the above query isn't my issue though - what I want to do is run it repeatedly for several different dates, and have that output be what gets fed through to Crystal for use in the report.
So say I want this query run for every Monday in September, I'd currently run the Crystal report once with a parameter of 07/09/2015, then again for 14/09/2015, etc.
I'd instead like to use my SELECT statement in conjunction with a query that tabulates this as needed - running the above once each per date required. With the output being something like:
Date Entitlement
07/09/2015 450,000.00
14/09/2015 460,123.00
21/09/2015 465,456.00
28/09/2015 468,789.00
Could someone point me in the right direction in terms of which keywords I should be reading up on here? I'd imagine it's quite straight-forward to generate a set of dates and run my SQL as a subquery using them, but I'm not sure where to start.
The only way I can think of without using a stored procedure is by repeating (i.e. copy/paste) your query for each date parameter and then combining them as sub-queries using UNION. Something like this:
SELECT SUM(e1.ENT_LOCAL_AMOUNT+e1.ENT_DISCRETIONARY_AMOUNT) AS "Entitlement"
FROM CLAIM_PERIODS cp1
JOIN ENTITLEMENTS e1
ON cp1.CPE_REFNO=e1.ENT_CPE_REFNO
WHERE e1.ENT_REFNO=(SELECT MAX(to_number(e2.ENT_REFNO))
FROM ENTITLEMENTS e2
WHERE e1.ENT_CPE_REFNO=e2.ENT_CPE_REFNO
AND (e2.ENT_START_DATE <= {?HB_As_At_Date_1}
AND e2.ENT_END_DATE > {?HB_As_At_Date_1})
AND e2.ENT_CREATED_DATE<={?HB_As_At_Date_1})
AND cp1.CPE_CPA_CPY_CODE='HB'
UNION
SELECT SUM(e1.ENT_LOCAL_AMOUNT+e1.ENT_DISCRETIONARY_AMOUNT) AS "Entitlement"
FROM CLAIM_PERIODS cp1
JOIN ENTITLEMENTS e1
ON cp1.CPE_REFNO=e1.ENT_CPE_REFNO
WHERE e1.ENT_REFNO=(SELECT MAX(to_number(e2.ENT_REFNO))
FROM ENTITLEMENTS e2
WHERE e1.ENT_CPE_REFNO=e2.ENT_CPE_REFNO
AND (e2.ENT_START_DATE <= {?HB_As_At_Date_2}
AND e2.ENT_END_DATE > {?HB_As_At_Date_2})
AND e2.ENT_CREATED_DATE<={?HB_As_At_Date_2})
AND cp1.CPE_CPA_CPY_CODE='HB'
As for your comment about writing a script for that, I don't know how you are running your report. But if you have an app/website running it, then you can generate the SQL in the app/website's language and assign it to the report object before you run it. Or even better, you can generate the SQL, run it, and assign the results to the report object. I do this all the time as I prefer my code to run the queries rather than the report itself, because I follow the layered design pattern in my app. The report will be located in the presentation layer which cannot communicate with the database directly, instead it calls the business/data layer with generates/runs the query and returns the results to the business/presentation layer.
Edit the parameter to take the input as multiple values and change the query as
Use either start or end but not both
SELECT SUM(e1.ENT_LOCAL_AMOUNT+e1.ENT_DISCRETIONARY_AMOUNT) AS "Entitlement"
FROM CLAIM_PERIODS cp1
JOIN ENTITLEMENTS e1
ON cp1.CPE_REFNO=e1.ENT_CPE_REFNO
WHERE e1.ENT_REFNO=(SELECT MAX(to_number(e2.ENT_REFNO))
FROM ENTITLEMENTS e2
WHERE e1.ENT_CPE_REFNO=e2.ENT_CPE_REFNO
AND e2.ENT_END_DATE in ( {?HB_As_At_Date})
AND e2.ENT_CREATED_DATE in ({?HB_As_At_Date})
AND cp1.CPE_CPA_CPY_CODE='HB'
Actually, there is a more elegant way to solve this problem.
Let's suppose that the main query is t1 , and the parameters to use are available in a table t2.
Here is an example, where the the sub-queries t1 and t2 can be replaced by real tables.
select t1.title , t2.ref_date, t2.dt_label
from (
select 'abc' title from dual union all
select 'def' title from dual
) t1
cross join
(
select to_date('01.07.2019', 'dd.mm.yyyy') ref_date,'S1/2019' dt_label from dual union all
select to_date('01.12.2019', 'dd.mm.yyyy') ref_date,'Y/2019' dt_label from dual union all
select to_date('01.07.2020', 'dd.mm.yyyy') ref_date,'S1/2020' dt_label from dual union all
select to_date('01.12.2020','dd.mm.yyyy') ref_date, 'Y/2020' dt_label from dual
) t2
where t2.ref_date < to_date('01.08.2020','dd.mm.yyyy')
order by t2.ref_date, t1.title;
This way, the query remain the same, while the extraction parameters are filled in an auxiliary table.
Related
I am in MS Access trying to join two queries. The first query is a Crosstab query:
TRANSFORM Sum(Q1.Downtime) AS SumOfDowntime
SELECT Q1.Batch
FROM [QryDowntime] Q1
GROUP BY Q1.Batch
PIVOT Q1.Category;
This runs, no issues. It is summing downtime for OEE for context. Output looks something like:
Batch Availability Performance Quality
1 0 5 2
2 3 1 5
...
I then have a separate query that pulls the date from the previous record:
SELECT B2.Batch,
(SELECT TOP 1 B1.LastPallet
FROM TblBatches AS B1
WHERE B1.ID < B2.ID
ORDER BY B1.ID DESC) AS PrevEnd
FROM TblBatches AS B2;
Again, no issues. This runs and the output looks something like:
Batch PrevEnd
1 8/2/2021
2 8/5/2021
...
I have a summary table and want to join these two.
SELECT B1.Batch,
Q1.Availability,
Q1.Performance,
Q1.Quality,
Q2.PrevEnd
FROM (TblBatches AS B1
LEFT JOIN QryCrosstab AS Q1 ON B1.Batch = Q1.Batch)
LEFT JOIN QryDate AS Q2 ON B1.Batch = Q2.Batch;
I thought this would be the easy part but I get the error "The Microsoft Access database engine does not recognize 'B2.ID' as a valid field name or expression." If I remove either of the joins, the query works fine.
I am aware of this solution but, as the author states, it is not really a solution. I do not want to use more tables if there is another way to fix the error.
I tried this solution but it is not quite the same. I don't really have a subquery I can do beforehand. If I can, I do not know how to do it. There is nothing dynamic. I am not accepting user inputs. These are straightforward queries. I am hoping there is a strange typo or incorrect syntax.
Any ideas would be greatly appreciated!
Not being an SQL expert, I am struggling with the following:
I inherited a larg-ish table (about 100 million rows) containing time-stamped events that represent stage transitions of mostly shortlived phenomena. The events are unfortunately recorded in a somewhat strange way, with the table looking as follows:
phen_ID record_time producer_id consumer_id state ...
000123 10198789 start
10298776 000123 000112 hjhkk
000124 10477886 start
10577876 000124 000123 iuiii
000124 10876555 end
Each phenomenon (phen-ID) has a start event and theoretically an end event, although it might not have been occured yet and thus not recorded. Each phenomenon can then go through several states. Unfortunately, for some states, the ID is recorded in either a product or a consumer field. Also, the number of states is not fixed, and neither is the time between the states.
To beginn with, I need to create an SQL statement that for each phen-ID shows the start time and the time of the last recorded event (could be an end state or one of the intermediate states).
Just considering a single phen-ID, I managed to pull together the following SQL:
WITH myconstants (var1) as (
values ('000123')
)
select min(l.record_time), max(l.record_time) from
(select distinct * from public.phen_table JOIN myconstants ON var1 IN (phen_id, producer_id, consumer_id)
) as l
As the start-state always has the lowest recorded-time for the specific phenomenon, the above statement correctly returns the recorded time range as one row irrespective of what the end state is.
Obviously here I have to supply the phen-ID manually.
How can I make this work that so I get a row of the start times and maxium recorded time for each unique phen-ID? Played around with trying to fit in something like select distinct phen-id ... but was not able to "feed" them automatically into the above. Or am I completely off the mark here?
Addition:
Just to clarify, the ideal output using the table above would like something like this:
ID min-time max-time
000123 10198789 10577876 (min-time is start, max-time is state iuii)
000124 10477886 10876555 (min-time is start, max-time is end state)
union all might be an option:
select phen_id,
min(record_time) as min_record_time,
max(record_time) as max_record_time
from (
select phen_id, record_time from phen_table
union all select producer_id, record_time from phen_table
union all select consumer_id, record_time from phen_table
) t
where phen_id is not null
group by phen_id
On the other hand, if you want prioritization, then you can use coalesce():
select coalesce(phen_id, producer_id, consumer_id) as phen_id,
min(record_time) as min_record_time,
max(record_time) as max_record_time
from phen_table
group by coalesce(phen_id, producer_id, consumer_id)
The logic of the two queries is not exactly the same. If there are rows where more than one of the three columns is not null, and values differ, then the first query takes in account all non-null values, while the second considers only the "first" non-null value.
Edit
In Postgres, which you finally tagged, the union all solution can be phrased more efficiently with a lateral join:
select x.phen_id,
min(p.record_time) as min_record_time,
max(p.record_time) as max_record_time
from phen_table p
cross join lateral (values (phen_id), (producer_id), (consumer_id)) as x(phen_id)
where x.phen_id is not null
group by x.phen_id
I think you're on the right track. Try this and see if it is what you are looking for:
select
min(l.record_time)
,max(l.record_time)
,coalesce(phen_id, producer_id, consumer_id) as [Phen ID]
from public.phen_table
group by coalesce(phen_id, producer_id, consumer_id)
I basically want to reuse an input to save the user from inputting same thing again..
Here's how the query looks like:
select * from table
where bb.bbn_from_dttm >= TO_DATE('&Bill_Date_ddmmyyyy','dd-mm-yyyy')
and bb.bbn_to_dttm <= LAST_DAY('&Bill_Date_ddmmyyyy');
I don't want the user inputting this twice and getting the value from the first input would give me the date range I need.
This is SQL Oracle.
Any clues?
Note the use of an inline view to convert the input string into a date (just once for the entire query) - then the rest of the query uses the date created in this inline view, not the user's input. Change & to && if you need the query to use the same input whenever run in the same session (although in most cases that's not what users would want).
select bb.*
from my_table bb
join
( select TO_DATE('&Bill_Date_ddmmyyyy','dd-mm-yyyy') as bill_date
from dual
) d
on bb.bbn_from_dttm >= d.bill_date and bb.bbn_to_dttm <= LAST_DAY(d.bill_date);
I want to extract perfectly match data, not partical match data.
But, I can't extract them, if I execute sql code of the below:
I estimate this sql code extract no data , but this extract all rows of data.
【SQL code】
WITH a AS(
SELECT
001 AS id_a,
112345678901234567 AS x
UNION ALL
SELECT
002,
112345678901233567
UNION ALL
SELECT
003,
112345678901232568
),
comp_a AS(
SELECT
*
FROM
a
WHERE
x IN(112345678901234000, 112345678901233000, 112345678901232000)
),
comp_b AS(
SELECT
004 AS id_b
UNION ALL
SELECT
005
)
SELECT
id_a,
id_b
FROM
comp_a
LEFT OUTER JOIN
comp_b
ON (
comp_a.id_a = comp_b.id_b
)
WHERE
comp_b.id_b IS NULL
;
I think "in" clauses are used for perfectly match.
But, perhaps, I think this sql code isn't executed "in" clauses , but it is executed "like" clauses.
I will be glad you answer solution of my question.
■Further note:
・I deleted cashe of browser and Bigquery. But I couldn't solve it.
・This sql code is sample code , because I can't expose real sql code.
・I can recreate this problem in One enviroment of BigQuery,
but I can't recreate in Other enviroment of BigQuery.
This Problem may be not problem of sql code , but problem of enviroment
or setting.
Thank you for answering my question.
I solved my question.
The cause of my problem is not BigQuery , but it is the format of Excel.
Detail:
I tried to check data using Excel , Because the results are a lot of data.
Sad to say , Because of the format of Excel is numeric type , a part of number data are rounded. So I misunderstood the correct result to the wrong result.
Sorry about my misunderstanding.
I'm in need of some assistance. I have search and not found what I'm looking for. I have an assigment for school that requires me to use SQL. I have a query that pulls some colunms from two tables:
SELECT Course.CourseNo, Course.CrHrs, Sections.Yr, Sections.Term, Sections.Location
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring";
I need to add a Totals row at the bottom to count the CourseNo and Sum the CrHrs. It has to be done through SQL query design as I need to paste the code. I know it can be done with the datasheet view but she will not accept that. Any advice?
To accomplish this, you can union your query together with an aggregation query. Its not clear from your question which columns you are trying to get "Totals" from, but here's an example of what I mean using your query and getting counts of each (kind of useless example - but you should be able to apply to what you are doing):
SELECT
[Course].[CourseNo]
, [Course].[CrHrs]
, [Sections].[Yr]
, [Sections].[Term]
, [Sections].[Location]
FROM
[Course]
INNER JOIN [Sections] ON [Course].[CourseNo] = [Sections].[CourseNo]
WHERE [Sections].[Term] = [spring]
UNION ALL
SELECT
"TOTALS"
, SUM([Course].[CrHrs])
, count([Sections].[Yr])
, Count([Sections].[Term])
, Count([Sections].[Location])
FROM
[Course]
INNER JOIN [Sections] ON [Course].[CourseNo] = [Sections].[CourseNo]
WHERE [Sections].[Term] = “spring”
You can prepare your "total" query separately, and then output both query results together with "UNION".
It might look like:
SELECT Course.CourseNo, Course.CrHrs, Sections.Yr, Sections.Term, Sections.Location
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring"
UNION
SELECT "Total", SUM(Course.CrHrs), SUM(Sections.Yr), SUM(Sections.Term), SUM(Sections.Location)
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring";
Whilst you can certainly union the aggregated totals query to the end of your original query, in my opinion this would be really bad practice and would be undesirable for any real-world application.
Consider that the resulting query could no longer be used for any meaningful analysis of the data: if displayed in a datagrid, the user would not be able to sort the data without the totals row being interspersed amongst the rest of the data; the user could no longer use the built-in Totals option to perform their own aggregate operation, and the insertion of a row only identifiable by the term totals could even conflict with other data within the set.
Instead, I would suggest displaying the totals within an entirely separate form control, using a separate query such as the following (based on your own example):
SELECT Count(Course.CourseNo) as Courses, Sum(Course.CrHrs) as Hours
FROM Course INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term = "spring";
However, since CrHrs are fields within your Course table and not within your Sections table, the above may yield multiples of the desired result, with the number of hours multiplied by the number of corresponding records in the Sections table.
If this is the case, the following may be more suitable:
SELECT Count(Course.CourseNo) as Courses, Sum(Course.CrHrs) as Hours
FROM
Course INNER JOIN
(SELECT DISTINCT s.CourseNo FROM Sections s WHERE s.Term = "spring") q
ON Course.CourseNo = q.CourseNo