How to calculate Fuctuation % select statement with a number of variables? - select

I need to write a query for a fluctuation report month to month.
For monthly consumption I have start and end readings that I use to calculate consumption. From this calculated value I need to to find the fluctuation of month to month.
Code used
select distinct
c.CNAME as MeterPointName,
m.SNUMBER as SerialNumber,
bill.RDATE as BillingPeriod,
IF(bill.E1 > bill1.E1 and bill.BRID = bill1.BRID, (bill.E1 - bill1.E1), 0) as Consumption,
IF(bill.E1 > bill1.E1 and DATE(bill.RDATE) > DATE(bill1.RDATE), ((bill.E1 - bill1.E1)/(bill.E1-bill1.E1)), 0) as Fluctuation
from table1.CUSTOMER c
RIGHT JOIN table2.METER m on c.CNUMBER = m.MNAME
LEFT JOIN table3.BILLMTOTAL bill on m.MNAME = bill.CNUMBER
LEFT JOIN table3.BILLMTOTAL bill1 on bill.SNUMBER = bill1.SNUMBER
RIGHT JOIN table4.CUSTOMERTREE cust on c.ID = cust.Customer_id
where bill.RP = 'E'
and bill1.RP = 'S'
and bill.BRID between 179 and 190
and bill.BRID = bill1.BRID
and date(bill.RDATE) > date(bill1.RDATE)
and cust.lft between 2185 and 2633
GROUP BY m.SNUMBER, bill.BRID, bill.E1
ORDER BY bill.RDATE
bill1.E1 and bill2.E1 are the start and end readings.
Example :
bill.E1 - 5
bill.E2 - 10
Everything works as it should just the fluctuation figure is not right.

Related

How to have CASE statement look at previous records in the statement

I have the following code generating a case statement in which I would like all future time periods to return 'Graduated' if the student graduated in a previous time period. Here is the current code:
SELECT DISTINCT
Z1.StudentID,
Z1.AcadLevel,
Z1.StudentAcadLevel,
Z1.StudentCohortStartDate,
Z1.PeriodID,
Z2.CourseTimePeriod,
Z3.DegreeTimePeriod,
CASE
WHEN Z1.PeriodID = '0' THEN 'CohortStart'
WHEN Z3.DegreeTimePeriod <= Z1.PeriodID THEN 'Graduated'
WHEN Z1.PeriodID = Z2.CourseTimePeriod THEN 'Retained'
WHEN Z2.CourseTimePeriod IS NULL THEN 'Churned'
ELSE 'Fix Me'
END AS TimePeriodStatus
FROM Z_Retention_StudentTimePeriodStatus Z1
LEFT OUTER JOIN Z_Retention_StudentCourseRegistrations Z2 ON Z2.StudentID = Z1.StudentID AND Z2.STC_ACAD_LEVEL = Z1.AcadLevel AND Z2.CourseTimePeriod = Z1.PeriodID
LEFT OUTER JOIN Z_Retention_StudentDegree Z3 ON Z3.StudentID = Z1.StudentID AND Z3.DegreeAcadLevel = Z1.AcadLevel AND Z3.DegreeTimePeriod = Z1.PeriodID
ORDER BY Z1.StudentID, Z1.PeriodID, Z2.CourseTimePeriod
In the attached image, I'm hoping to add a line to the case statement that would make the highlighted rows return 'Graduated' rather than 'Churned'.

Optimizing Postgres query with timestamp filter

I have a query:
SELECT DISTINCT ON (analytics_staging_v2s.event_type, sent_email_v2s.recipient, sent_email_v2s.sent) sent_email_v2s.id, sent_email_v2s.user_id, analytics_staging_v2s.event_type, sent_email_v2s.campaign_id, sent_email_v2s.recipient, sent_email_v2s.sent, sent_email_v2s.stage, sent_email_v2s.sequence_id, people.role, people.company, people.first_name, people.last_name, sequences.name as sequence_name
FROM "sent_email_v2s"
LEFT JOIN analytics_staging_v2s ON sent_email_v2s.id = analytics_staging_v2s.sent_email_v2_id
JOIN people ON sent_email_v2s.person_id = people.id
JOIN sequences on sent_email_v2s.sequence_id = sequences.id
JOIN users ON sent_email_v2s.user_id = users.id
WHERE "sent_email_v2s"."status" = 1
AND "people"."person_type" = 0
AND (sent_email_v2s.sequence_id = 1888) AND (sent_email_v2s.sent >= '2016-03-18')
AND "users"."team_id" = 1
When I run EXPLAIN ANALYZE on it, I get:
Then, if I change that to the following (Just removing the (sent_email_v2s.sent >= '2016-03-18')) as follows:
SELECT DISTINCT ON (analytics_staging_v2s.event_type, sent_email_v2s.recipient, sent_email_v2s.sent) sent_email_v2s.id, sent_email_v2s.user_id, analytics_staging_v2s.event_type, sent_email_v2s.campaign_id, sent_email_v2s.recipient, sent_email_v2s.sent, sent_email_v2s.stage, sent_email_v2s.sequence_id, people.role, people.company, people.first_name, people.last_name, sequences.name as sequence_name
FROM "sent_email_v2s"
LEFT JOIN analytics_staging_v2s ON sent_email_v2s.id = analytics_staging_v2s.sent_email_v2_id
JOIN people ON sent_email_v2s.person_id = people.id
JOIN sequences on sent_email_v2s.sequence_id = sequences.id
JOIN users ON sent_email_v2s.user_id = users.id
WHERE "sent_email_v2s"."status" = 1
AND "people"."person_type" = 0
AND (sent_email_v2s.sequence_id = 1888) AND "users"."team_id" = 1
when I run EXPLAIN ANALYZE on this query, the results are:
EDIT:
The results above from today are about as I expected. When I ran this last night, however, the difference created by including the timestamp filter was about 100x slower (0.5s -> 59s). The EXPLAIN ANALYZE from last night showed all of the time increase to be attributed to the first unique/sort operation in the query plan above.
Could there be some kind of caching issue here? I am worried now that there might be something else going on (transiently) that might make this query take 100x longer since it happened at least once.
Any thoughts are appreciated!

How to find amounts greater than zero before a specified date

Currently I am trying to find the outstanding balance of an account before a certain specified date.
below is my query
SELECT
TRANS.AMTUNRES UNPAID,
TRANS.TRANTYPE,
TRANS.INCPROVCODE IPROV,
ACHOLDERACH.ACBALANCE BALANCE,
ACHOLDERANY.PREFORMATTEDINTERN ACCOUNTNAMECHART,
WHENPAY,
ChartNo
FROM TRANS
LEFT JOIN ACHOLDER ACHOLDERACH ON ACHOLDERACH.ACHOLDERID = TRANS.ACHOLDERID
LEFT JOIN ANYBODY ACHOLDERANY ON ACHOLDERANY.ANYBODYID = TRANS.ACHOLDERID
LEFT JOIN INVPAYRESOLN ON ACHOLDERACH.ACHOLDERID = INVPAYRESOLN.ACHOLDERID
left join anybody on trans.anybodyid = anybody.anybodyid
where TRANS.AMTUNRES <> '0.00' and
ACHOLDERACH.ACBALANCE <> '0.00' and
WhenPay between '01-01-2012' and '04-07-2016'
and chartNo = '123456789'

Compare results with percentage with PRINT

I've queried the results I'm looking for, now I simply want to compare "OnTime" Y/N for a percentage "OnTime", but I'm having trouble comparing the alias and/or using the column name in the PRINT function. Any suggestions?
SELECT
shmast.fcnumber AS Customer,
shmast.fcbcompany AS Company,
somast.fsono AS SalesOrder,
somast.fduedate AS DueDate,
shmast.fshipno AS Shipper,
shmast.fshipdate AS ShipDate,
--DATEDIFF(DAY,somast.fduedate,shmast.fshipdate) AS 'Days',
CASE
WHEN shmast.fshipdate <= somast.fduedate THEN 'Y'
WHEN shmast.fshipdate > somast.fduedate THEN 'N'
END AS OnTime
FROM somast
JOIN shmast ON somast.fsono = shmast.fcsono
WHERE shmast.fcnumber = '000111'
PRINT (OnTime = 'Y') / COUNT (*)
/*GROUP BY
shmast.fcnumber,
shmast.fcbcompany,
somast.fsono,
somast.fduedate,
shmast.fshipno,
shmast.fshipdate*/
Giving it another shot after your description
SELECT
sum(CASE WHEN shmast.fshipdate<=somast.fduedate THEN 100.0 END)/count(*) AS OnTime
FROM somast
JOIN shmast ON somast.fsono = shmast.fcsono
WHERE shmast.fcnumber = '000111'

How to select first and last records between certain date parameters?

I need a Query to extract the first instance and last instance only between date parameters.
I have a Table recording financial information with financialyearenddate field linked to Company table via companyID. Each company is also linked to programme table and can have multiple programmes. I have a report to pull the financials for each company
on certain programme which I have adjusted to pull only the first and last instance (using MIN & MAX) however I need the first instance.
after a certain date parameter and the last instance before a certain date parameter.
Example: Company ABloggs has financials for 1999,2000,2001,2004,2006,2007,2009 but the programme ran from 2001 to 2007 so I only want
the first financial record and last financial record between those years i.e. 2001 & 2007 records. Any help appreciated.
At the moment I am using 2 queries as I needed the data in a hurry but I need it in 1 query and only where financial year end dates are between parameters and only where there are minimum of 2 GVA records for a company.
Query1:
SELECT
gva.ccx_companyname,
gva.ccx_depreciation,
gva.ccx_exportturnover,
gva.ccx_financialyearenddate,
gva.ccx_netprofitbeforetax,
gva.ccx_totalturnover,
gva.ccx_totalwages,
gva.ccx_statusname,
gva.ccx_status,
gva.ccx_company,
gva.ccx_totalwages + gva.ccx_netprofitbeforetax + gva.ccx_depreciation AS GVA,
gva.ccx_nofulltimeequivalentemployees
FROM
(
SELECT
ccx_companyname,
MAX(ccx_financialyearenddate) AS LatestDate
FROM Filteredccx_gva AS Filteredccx_gva_1
GROUP BY ccx_companyname
) AS min_1
INNER JOIN Filteredccx_gva AS gva
ON min_1.ccx_companyname = gva.ccx_companyname AND
min_1.LatestDate = gva.ccx_financialyearenddate
WHERE (gva.ccx_status = ACTUAL)
Query2:
SELECT
gva.ccx_companyname,
gva.ccx_depreciation,
gva.ccx_exportturnover,
gva.ccx_financialyearenddate,
gva.ccx_netprofitbeforetax,
gva.ccx_totalturnover,
gva.ccx_totalwages,
gva.ccx_statusname,
gva.ccx_status,
gva.ccx_company,
gva.ccx_totalwages + gva.ccx_netprofitbeforetax + gva.ccx_depreciation AS GVA,
gva.ccx_nofulltimeequivalentemployees
FROM
(
SELECT
ccx_companyname,
MIN(ccx_financialyearenddate) AS FirstDate
FROM Filteredccx_gva AS Filteredccx_gva_1
GROUP BY ccx_companyname
) AS MAX_1
INNER JOIN Filteredccx_gva AS gva
ON MAX_1.ccx_companyname = gva.ccx_companyname AND
MAX_1.FirstDate = gva.ccx_financialyearenddate
WHERE (gva.ccx_status = ACTUAL)
Can't you just add a where clause using the first and last date parameters. Something like this:
SELECT <companyId>, MIN(<date>), MAX(<date>)
FROM <table>
WHERE <date> BETWEEN #firstDate AND #lastDate
GROUP BY <companyId>
declare #programme table (ccx_companyname varchar(max), start_year int, end_year int);
insert #programme values
('ABloggs', 2001, 2007);
declare #companies table (ccx_companyname varchar(max), ccx_financialyearenddate int);
insert #companies values
('ABloggs', 1999)
,('ABloggs', 2000)
,('ABloggs', 2001)
,('ABloggs', 2004)
,('ABloggs', 2006)
,('ABloggs', 2007)
,('ABloggs', 2009);
select c.ccx_companyname, min(ccx_financialyearenddate), max(ccx_financialyearenddate)
from #companies c
join #programme p on c.ccx_companyname = p.ccx_companyname
where c.ccx_financialyearenddate >= p.start_year and c.ccx_financialyearenddate <= p.end_year
group by c.ccx_companyname
having count(*) > 1;
You can combine your two original queries into a single query by including the MIN and MAX aggregates in the same GROUP BY query of the virtual table. Also including COUNT() and HAVING COUNT() > 1 ensures company must have at least 2 dates. So query should look like:
SELECT
gva.ccx_companyname,
gva.ccx_depreciation,
gva.ccx_exportturnover,
gva.ccx_financialyearenddate,
gva.ccx_netprofitbeforetax,
gva.ccx_totalturnover,
gva.ccx_totalwages,
gva.ccx_statusname,
gva.ccx_status,
gva.ccx_company,
gva.ccx_totalwages + gva.ccx_netprofitbeforetax + gva.ccx_depreciation AS GVA,
gva.ccx_nofulltimeequivalentemployees
FROM
(SELECT
ccx_companyname,
ccx_status,
MIN(ccx_financialyearenddate) AS FirstDate,
MAX(ccx_financialyearenddate) AS LastDate,
COUNT(*) AS NumDates
FROM Filteredccx_gva AS Filteredccx_gva_1
WHERE (ccx_status = ACTUAL)
GROUP BY ccx_companyname, ccx_status
HAVING COUNT(*) > 1
) AS MinMax
INNER JOIN Filteredccx_gva AS gva
ON MinMax.ccx_companyname = gva.ccx_companyname AND
(MinMax.FirstDate = gva.ccx_financialyearenddate OR
MinMax.LastDate = gva.ccx_financialyearenddate)
WHERE (gva.ccx_status = MinMax.ccx_status)
ORDER BY gva.ccx_companyname, gva.ccx_financialyearenddate