MySQL Case Statement for proper bucketing - mysql

reposting this question as I am still struggling to find the right solution.
I was able to isolate the 'OA' only scenarios and flag them appropriately as NA. However I am having trouble isolating the 'I' only events as well as properly aging the EquipID's that have both I and OA events.
This is the logic I am using for aging right now and it works great for 'I' only events, but properly isolating the 'I' and 'OA' EquipID's and then getting the difference between the two dates is eluding me.
datediff(curdate(),concat(left(eventDateTime,4),'-',mid(eventDateTime,5,2),'-',mid(eventDateTime,7,2))) as age_in_depot
I tried grouping by the EquipID but of course that gives me only one eventDateTime result and it is always the first result, which in the case of an 'I' and 'OA' it's only the 'I' eventDateTime.
I also have logic to identify the 'I' and 'OA' events, but this only works correctly if I am intending on grouping the EquipmentID's together to one line, which noted above, drops the 2nd eventDateTime entry needed to properly age these EquipID's.
GROUP_CONCAT( DISTINCT StatusCD) as StatusCD
Any help or insight is greatly appreciated. Once I have this 'I' only event flagged and aging I can finally finish out this dashboard I am building for our team.
Thank you in advance.
J

Pivot the table so you get the in and out dates into separate columns for the same EquipID. Then you can subtract them, and apply appropriate defaults for the missing dates.
SELECT EquipID, InDate, OutDate, StatusCD_N,
CASE WHEN InDate AND OutDate THEN DATEDIFF(OutDate, InDate)
WHEN InDate THEN DATEDIFF(CURDATE(), InDate)
ELSE 'N/A' -- only OutDate
END AS AgeInDepot
FROM (
SELECT EquipID, GROUP_CONCAT(StatusCD) AS StatsuCD_N,
MAX(IF(StatusCD = 'I', DATE(STR_TO_DATE(eventDateTime, '%Y%m%d%H%i')), NULL) AS InDate,
MAX(IF(StatusCD = 'OA', DATE(STR_TO_DATE(eventDateTime, '%Y%m%d%H%i')), NULL) AS OutDate
FROM yourTable
GROUP BY EquipID
) AS x

Related

Reducing two views into one?

Good afternoon all,
I am new to mySQL. I have everything working just as I want it, but I could only achieve what I wanted by creating a first view, then referencing it in the final view. I wanted to know whether this is bad practice and will result in slower performance or not? And also, just for learning sake whether it could be all done by using a single view. I have tried and tried but keep getting errors.
First I create this view, which I call intermediate view:
CREATE VIEW intermediate_view AS (
SELECT
freight,
shipping_date,
receiver,
tracking_no,
left(cast(receiver as int), 3) as vendor_id,
DATEDIFF(now(),shipping_date) AS days_in_transit,
CASE
WHEN DATEDIFF(now(),shipping_date) > 5 then "Problem"
WHEN DATEDIFF(now(),shipping_date) < 0 then "Not shipped yet"
ELSE "In transit"
END
AS Status
FROM tracking
);
I'm then creating a final view to join data to it from another another table. My second view is
CREATE VIEW final_view AS (
SELECT
intermediate_view.freight,
intermediate_view.shipping_date,
intermediate_view.receiver,
intermediate_view.tracking_no,
intermediate_view.days_in_transit,
intermediate_view.Status,
vendors.vendor_name
FROM intermediate_view
JOIN vendors
on intermediate_view.vendor_id = vendors.vendor_id
);
Basically, all the second table is doing is matching the first 3 numbers of left(cast(receiver as int), 3), to another table table where those 3 numbers have a corresponding company name. Is there a way to join this in one view?
Hopefully I've explained this well enough! Thanks in advance
your cast will not work in MySQL, so use this
CREATE VIEW final_view AS (
SELECT
t.freight,
t.shipping_date,
t.receiver,
t.tracking_no,
left(cast(t.`receiver` as UNSIGNED), 3) as vendor_id,
DATEDIFF(now(),t.shipping_date) AS days_in_transit,
CASE
WHEN DATEDIFF(now(),t.shipping_date) > 5 then "Problem"
WHEN DATEDIFF(now(),t.shipping_date) < 0 then "Not shipped yet"
ELSE "In transit"
END
AS 'Status',
v.vendor_name
FROM tracking t JOIN
vendors v
on left(cast(t.`receiver` as UNSIGNED), 3) = v.vendor_id
);

SQL if query functionality

I want to write a query to determine the success rate for every day for each different mode. I did write a query that'll just group by date and mode which serves my purpose but one of my seniors wrote this following query which also works but I am just unable to understand how the if clause is working. I'll add a bit of the query here -
SELECT
dt,
sum(if(mode='A',success,0))AS a_s,
sum(if(mode='A',total,0))AS a_t,
sum(if(mode='B',success,0))AS b_s,
sum(if(mode='B',total,0))AS b_t,
sum(if(mode='C',success,0))AS c_s,
sum(if(mode='C',total,0))AS c_t,
sum(if(mode='D',success,0))AS d_s,
sum(if(mode='D',total,0))AS d_t,
sum(if(mode NOT in('A','B','C','D'),success,0))AS other_s,
sum(if(mode NOT in('A','B','C','D'),total,0))AS other_t
FROM
(SELECT
mode,
date(addedon)AS dt,
sum(if(status in('success','partial'),1,0))AS success,
count(*)AS total
FROM `a_huge_ass_table`
WHERE `studentid`=159633 AND addedon>'2021-01-15'
GROUP BY mode,date(addedon)
)AS t
Here I am unable to understand how sum(if(mode='A',success,0))AS a_s, - this if clause is working. If the condition is true then the clause is returning success? how does that work does adding success also somehow verify that its status is a success case? I cant find this on google.
First, if() is not standard SQL. I recommend rewrite this using case:
sum(case when mode = 'A' then success else 0 end) as a_s,
sum(case when mode = 'A' then total else 0 end) as a_t,
and so on.
Second, this query is missing the final group by dt. Otherwise it produces one row, rather than a separate row for each dt value.
This is called conditional aggregation. Every row in the final result set represents a group of rows from the subquery. Within this group, some have mode = 'A' and some do not. For the ones with mode = 'A' the above sums the value of success and total.
There is no need for a subquery by the way. That just slows down the query. I would recommend writing the query as:
SELECT date(addedon) as dt
SUM( mode = 'A' AND status IN ('success', 'partial') ) as a_success,
SUM( mode = 'A' ) as a_total,
. . .
FROM `a_huge_ass_table`
WHERE studentid = 159633 AND addedon >= '2021-01-15'
GROUP BY date(addedon);
Note that this uses a MySQL extension where boolean expressions are treated as integers, with "1" for true and "0" for false.

Query to find entries and transpose

I've got a machine log available in an SQL table. I can do a bit in SQL, but I'm not good enough to process the following:
In the data column there are entries containing "RUNPGM: Recipe name" and "RUNBRKPGM: Recipe name"
What I want is a view containing 4 columns:
TimeStamp RUNPGM
TimeStamp RUNBRKPGM
Recipe Name
Time Difference in seconds
There is a bit of a catch:
Sometimes the machine logs an empty RUNBRKPGM that should be ignored
The RUNBRKPGM is sometimes logged with an error message. This entry should also be ignored.
It's always the RUNBRKPGM entry with just the recipe name that's the actual end of the recipe.
NOTE: I understand this is not a full/complete answer, but with info available in question as of now, I believe it at least helps give a starting point since this is too complicated (and formatted) to put in the comments:
If Recipe is everything in the DATA field except the 'RUNPGM = ' part you can do somethign similar to this:
SELECT
-- will give you a col for TimeStamp for records with RUNPGM
CASE WHEN DATA LIKE 'RUNPGM%' THEN TS ELSE '' END AS RUNPGM_TimeStamp,
-- will give you a col for TimeStamp for records with RUNBRKPGM
CASE WHEN DATA LIKE 'RUNBRKPGM%' THEN TS ELSE '' END AS RUNBRKPGM_TimeStamp,
-- will give you everything after the RUNPGM = (which I think is the recipe you are referring to)
CASE WHEN DATA LIKE 'RUNPGM%' THEN REPLACE(DATA, 'RUNPGM = ', '' AS RUNPGM_Recipe,
-- will give you everything after the RUNBRKPGM = (which I think is the recipe you are referring to)
CASE WHEN DATA LIKE 'RUNBRKPGM:%' THEN REPLACE(DATA, 'RUNBRKPGM = ', '' AS RUNPGM_Recipe
FROM TableName
Im not sure what columns you want to get the Time Difference on though so I dont have that column in here.
Then if you need to do additional logic/formatting on the columns once they are separated you can put the above in a sub select.
As a first swing, I'd try the following:
Create a view that uses string splitting to break the DATA column into a its parts (e.g. RunType and RecipeName)
Create a simple select that outputs the recipe name and tstamp where the runtype is RUNPGM.
Then add an OUTER APPLY:
Essentially, joining onto itself.
SELECT
t1.RecipeName,
t1.TimeStamp AS Start,
t2.TimeStamp AS Stop
--date func to get run time, pseudo DATEDIFF(xx,t1.TimeStamp, t2.TimeStamp) as RunTime
FROM newView t1
OUTER APPLY ( SELECT TOP ( 1 ) *
FROM newView x
WHERE x.RecipeName = t1.RecipeName
AND RunType = 'RUNBRKPGM'
ORDER BY ID DESC ) t2
WHERE t1.RunType = 'RUNPGM';

SSRS not inclusive for dates; While Management Studio is?

Why is it that when I run the query in Management Studio with the following where clause, it returns the data correctly when the cash_date equals the parameter, FromDate.
FILMTRAN.cash_date >= (#FromDate) AND
However, when I copy the same query to SSRS it no longer includes the data where the #FromDate equals the cash_date. The user enters in the parameter in SSRS. I even did a test where I displayed the full date including the time and did an if statement that returned "yay" if they matched or "no" if they did not. Even according to SSRS, they match, but than why is my data not being returned when it occured on the same day?! I am dumbfounded this is not working, when it clearly works in management studio.
I have even tried adding a dateadd function into my sql statement, which again responds correctly in management studio but not ssrs.
Edit: I tested the >= using a much simpler 3 line query and it worked as intended but it is still not working for my query, which works in management studio but not SSRS. So now I am thinking there is some very specific bug associated with something in my longer query which I have attached. To test my code in management studio I declare the variables as seen below. However, I delete this code when I import my query into SSRS and instead create the parameters within SSRS(just as I have always done, with no problems).
DECLARE #FromDate AS DATETIME
SET #FromDate = '1-Oct-2013'
DECLARE #ToDate AS DATETIME
SET #ToDate = '8-Apr-2015'
DECLARE #Loan AS VARCHAR(20)
SET #Loan = 'TAX_B'
SELECT distinct LOANMAST.loan,
CARDINDX.DESCRIPTION AS BorrowerName,
CARDINDX.contact_name,
CARDINDX.in_care_of,
--loan_ipt.interest,
CARDINDX.mail_address1,
CARDINDX.mail_address2,
CARDINDX.mail_city,
CARDINDX.mail_state,
CARDINDX.mail_country,
LOANMAST.closed_date,
PROPERTY.STATE,
CARDINDX.MAIL_ZIP_CODE,
PROPERTY.address1,
PROPERTY.address2,
PROPERTY.city,
PROPERTY.ZIPCODE,
PROPERTY.country,
FILMTRAN.cash_date,
CASE FILMTRAN.TRAN_SUBTYPE WHEN 'REGINST' THEN 'Regular Collections'
WHEN 'PAC' THEN 'PAC'
WHEN 'CORREST' THEN 'Group Collection'
WHEN 'ESCROWTAX' THEN 'Tax Disbursement'
WHEN 'SUNDRY' THEN 'Tax Refund'
WHEN 'FULL PAY' THEN 'Payoff'
END AS TRANSUBTYPE,
FILMTRAN.TAX_ESCROW,
FILMTRAN.TRANSACTION079,
JK.taxescrowbalance,
CASE FILMTRAN.TRANSACTION079 WHEN 'COLLECTION' THEN FILMTRAN.TAX_ESCROW
WHEN 'DISBURSEMENT' THEN 0
END AS TAXESCROWCOLL,
CASE FILMTRAN.TRANSACTION079 WHEN 'DISBURSEMENT' THEN FILMTRAN.TAX_ESCROW *-1
WHEN 'COLLECTION' THEN 0
END AS TAXESCROWDIS
FROM LOANMAST LEFT OUTER JOIN BORROWER ON LOANMAST.loan=BORROWER.loan
LEFT OUTER JOIN LOANCOLL ON LOANMAST.loan=LOANCOLL.loan
LEFT OUTER JOIN PROPERTY ON LOANCOLL.code=PROPERTY.prop_code
LEFT OUTER JOIN BALHIST ON BALHIST.loan=LOANMAST.loan
LEFT OUTER JOIN CARDINDX ON BORROWER.SHORT_NAME=CARDINDX.SHORT_NAME
LEFT OUTER JOIN LOAN_IPT ON LOAN_IPT.short_name=CARDINDX.short_name
LEFT OUTER JOIN FILMTRAN ON FILMTRAN.loan=LOANMAST.loan
JOIN (
SELECT distinct FILMTRAN.loan, FILMTRAN.cash_date, FILMTRAN.transaction079 ,FILMTRAN.tax_escrow,
sum(FT.taxescrowcoll)+sum(FT.taxescrowdis)+isnull(BH.esc_tax_bal_p, 0) AS "TaxEscrowBalance"
from
FILMTRAN
LEFT OUTER JOIN (SELECT loan, accounting_date, esc_tax_bal_p,
rank () over (order by accounting_date desc) AS date_rank
FROM BALHIST
where loan = #Loan) BH ON BH.loan=FILMTRAN.loan
JOIN
(
SELECT loan, cash_date,
FILMTRAN.transaction079,
CASE FILMTRAN.TRANSACTION079 WHEN 'COLLECTION' THEN TAX_ESCROW
WHEN 'DISBURSEMENT' THEN 0
END AS TAXESCROWCOLL,
CASE FILMTRAN.TRANSACTION079 WHEN 'DISBURSEMENT' THEN TAX_ESCROW *-1
WHEN 'COLLECTION' THEN 0
END AS TAXESCROWDIS FROM FILMTRAN
WHERE loan = #Loan)
FT ON FT.loan=FILMTRAN.loan
where FT.cash_date <= FILMTRAN.cash_date
AND (BH.date_rank ='1' OR BH.accounting_date IS NULL)
AND (len(FT.transaction079) <= len(FILMTRAN.transaction079) OR FT.cash_date < FILMTRAN.cash_date)
GROUP BY FILMTRAN.loan,FILMTRAN.cash_date, FILMTRAN.transaction079, FILMTRAN.TAX_ESCROW, BH.esc_tax_bal_p) JK ON JK.loan=FILMTRAN.loan AND JK.cash_date = FILMTRAN.cash_date AND JK.transaction079=FILMTRAN.transaction079
WHERE
FILMTRAN.RVRS_REASON <> 'ERROR_CORR' AND
Loancoll.prim_ind = 'Y' AND
LOANMAST.loan_status <> '1_INQUIRY' AND
LOANMAST.loan_status <> '2_APP_ISS' AND
LOANMAST.loan_status <> '3_APP_ACC' AND
LOANMAST.loan_status <> '4_APPROVED' AND
LOANMAST.loan_status <> '5_COMMITTED' AND
LOANMAST.loan_status <> '9_DELN_SLF' AND
LOANMAST.loan_status <> '9_REJ_BRWR' AND
FILMTRAN.cash_date >= (#FromDate)
AND FILMTRAN.cash_date <= (#ToDate)
AND LOANMAST.loan = #Loan
AND FILMTRAN.tax_escrow <> 0
You have a date formatting issue.
Hopefully you are calling a stored procedure to generate your dataset.
If not, you should be!
To see what is happening you might want to output the dates that are getting passed through into a table - then have a look at that table once you have run the report. Obviously you will drop this table once your debugging is complete.
Make sure you store the dates in this table as text rather than DateTime.
Have a look at the diffrences when you run from SSRS and Management Studio.
I was unable to replicate this issue. In my system, using SSRS-2008, the results in SSRS are the same as in SQl-Server. I'm using a where clause with an SSRS parameter and a >= operator. I tested with both Text and Date/Time parameter types, and both worked fine.
I would suggest that you make sure that the datasource is the same as what you are querying in SQL server. Also, try entering the date without a time, if you are entering a time in the parameter.
For further assistance, please post your complete query (or a facsimile) and information on your table and parameter settings in SSRS.
EDIT:
Just taking a look at your query here, and I have a feeling that this may be the problem area:
where FT.cash_date <= FILMTRAN.cash_date
AND (BH.date_rank ='1' OR BH.accounting_date IS NULL)
AND (len(FT.transaction079) <= len(FILMTRAN.transaction079) OR FT.cash_date < FILMTRAN.cash_date)
Possibly could be stemming from confusion over the use of Filmtran without aliasing within the subquery, when it is already included in the main query? I would run the query without the two sub-queries in the From clause and see if the dates are as you'd expect, the add back in the subqueries one by one to determine the location of the issue.
Ok so the solution to my problem was dumber than I would like to admit. So in addition to stating my solution I will also suggest potential problems/solutions that relate to dates in SSRS/Management Studio:
Check the filters on the dataset within SSRS! This was my problem since I used a report template that had filters already on the dataset, even though I usually do all filters by hand in SQL management studio. (See picture below)
Make sure the time is correct, not just the date. For example, 10/1/2013 might appear but the actual value behind that date is something like 10/1/2013 5:43 PM. So then doing <= will not work if you are trying to include values that happened after 10/1/2013 5:43 PM but before 10/2/2013.
Make sure the regional date settings are the same for SSRS and SQL Server. For example, if one machine views dates in the European format of DD/MM/YYYY then it could cause problems if another user's machine is expecting the date to be in MM/DD/YYYY format.

MySQL query returns too many results with double join

Ok I'm trying to return these 4 values for any entry in simacc_payments that has a verified value of 0.
SELECT themes.value, members.real_name, simacc_payments.pay_amt, simacc_payments.pay_date
FROM simacc_payments
INNER JOIN members
ON simacc_payments.id_member = members.id_member
INNER JOIN themes
ON simacc_payments.id_member = themes.id_member
WHERE verified = "0"
ORDER BY members.real_name ASC, simacc_payments.pay_date DESC
The array I'm getting out as my result comes out like this, simplied
real_name, id_member, pay_amt, pay_date
real_name, value, pay_amt, pay_date
real_name, id_member, payments.pay_amt, payments.pay_date
real_name, value, pay_amt, pay_date
So every second entry in the array is correct, I know this has something to do with the join but I can't for the life of me figure out how to fix it. Please someone give me the answer while I still have some hair left :)
So just for anyone who ends up here with similar problems. My issues was cause by a second value in my Themes table for each use. Essentially I had to add an extra condition to my WHERE clause to filter these out. Hope that helps someone.