SQL join or PHP loop? or what? - php

So i have two queries to give me the information i need and im trying to figure out the best way to get the result from them. i have a table of Holdings. using:
SELECT symbol, sum(shares) AS shares, sum(shares * price) AS cost
FROM Transactions
WHERE (action <>5)
AND date <= '2010-10-30'
GROUP BY symbol HAVING sum(shares) > 0
which results in
AGNC 50.00 1390.0000
RSO 1517.00 9981.8600
T 265.00 6668.7500
I then have another query
SELECT close FROM History WHERE symbol = $symbol AND date = $date
which will return the closing price of that day.
T 24.40
i want to basically for a given date calculate value so sum(shares * close) for each symbol. but i dont know how to do that with out looping through each row in php. i was hoping there was a join or something i could do in sql to make the data return the way i want it

I think you could do something similar to this: A select query selecting a select statement Put your second query literally in your first query. Not sure about exact syntax, but like:
SELECT
symbol,
sum(shares) AS shares,
sum(shares * price) AS cost,
sum(shares * close) as value
FROM Transactions
INNER JOIN History ON (symbol = $symbol AND date = $date)
WHERE (action <>5)
AND date <= '2010-10-30'
GROUP BY symbol HAVING sum(shares) > 0
#popnoodles is right about your naming though. If you use date I'd think you'd need [date].

Related

Get Last Payment From A User in SQL

I have this table
I am trying to get the sum of principal + interest from the last transaction date. Column 4. is the last transaction performed - [No column name] is the transaction date
What I have tried so far:
select sum(h.principal+h.interest) as amt_paid, MAX(h.trx_date)
from Loanhist h WHERE h.ac_no = '$id' and h.trx_type='LP'
GROUP BY principal, interest
The test data generation is for Oracle, but you should easily be able to adapt it. The actual query will work on SQL server. You'll need to use an approach like this if the account can post more than one transaction in a day. Otherwise the 'LIMIT/TOP 1' approaches in the other answers will work fine.
CREATE GLOBAL TEMPORARY TABLE balances
( ac_no CHAR(100),
principal FLOAT,
interest FLOAT,
tranDate DATE
)
ON COMMIT PRESERVE ROWS;
INSERT INTO balances VALUES (1,123.123,.456,DATE '2017-01-01');
INSERT INTO balances VALUES (1,100,.456,DATE '2017-01-02');
INSERT INTO balances VALUES (1,200,.1,DATE '2017-01-02');
INSERT INTO balances VALUES (2,200,.1,DATE '2017-01-02');
INSERT INTO balances VALUES (2,300,.1,DATE '2017-01-02');
SELECT SUM
( CASE WHEN tranDate = max_tran_date
THEN principal + interest
ELSE 0
END
) AS tranSum
FROM (SELECT sub.*,
MAX(tranDate) OVER() AS max_tran_date
FROM balances sub
) BAL;
Your question is not really clear. But if you just want to get the last transaction performed by the user, the best thing to do will be to rely on IDs instead of dates.
SELECT TOP 1 * FROM Loanhist h WHERE h.trx_type='LP' ORDER BY h.ac_no DESC
try to use LIMIT keyword.For Example, Select * from table name where condition LIMIT 1.It will return first row
Try this:
SELECT TOP 1 sum(h.principal+h.interest) as amt_paid, h.trx_date
FROM Loanhist h WHERE h.ac_no = '$id' AND h.trx_type='LP'
ORDER BY h.ac_no DESC;

How to avoid slow execution time in php when database has a lot of data

My code is taking a lot of time to execute as my database has lots of data. Initially when there were 5000 rows it worked fine, but now my data has increased and it takes approximately 2 minutes to load. My PHP code is:
$result=$db->query("SELECT DateLastSaved,MDid,FileName FROM InitialLog");
$filesarray=array();
$datearray=array();
while($row3=mysqli_fetch_array($result))
{
$tobestored=$row3['MDid']."||".$row3['FileName'];
$key=array_search($tobestored,$filesarray);
$date=$row3['DateLastSaved'];
if(!is_numeric($key))
{
$filesarray[]=$tobestored;
$datearray[]=$date;
}
else
{
$aryear=date("Y",strtotime($datearray[$key]));
$armonth=date("m",strtotime($datearray[$key]));
$arday=date("d",strtotime($datearray[$key]));
$pryear=date("Y",strtotime($date));
$prmonth=date("m",strtotime($date));
$prday=date("d",strtotime($date));
if($aryear==$pryear && $armonth==$prmonth)
{
if($prday>$arday)
{
$datearray[$key]=$date;
}
}
}
}
Array is taking a lot of time in this code.
(From a comment). My purpose is to get all the file names of each MD as well as Date Last saved. If from the list, a specific file is repeated and is present in January, February and so on, I want the file from January only, that is the oldest month and also from that month I want the last in that month, that is if it exists on 1st Jan, 2nd jan, 30th jan, I would like to get the 30th Jan one.
Try to use HashMap.
In php terms it is simple associative array.
$key=$row3['MDid']."||".$row3['FileName'];
$date=$row3['DateLastSaved'];
if(!isset($datearray[$key]))
{
$datearray[$key]=$date;
}
else
{
...
}
It has constant key search time and should be excellent for task you tried to solve.
Your specification (presented in a comment on your question) is this:
For each distinct value of MDid -- for each doctor -- ...
Find the first month in which your table contains any row ...
Then find the latest row in that first month, and ...
Present that row in the result set.
Pro tip: try to formulate this kind of specification as clearly as possible before starting to write code. The hairier the specification, the more important it is to have clarity. This specification has hair.
Let's build this up as a MySQL query. First, you need to find the first month each MDid appears. This subquery does that using LAST_DAY(). In this application, think of LAST_DAY(date) as meaning MONTH_AND_YEAR_OF(date).
SELECT MDid, MIN(LAST_DAY(DateLastSaved)) FirstMonth
FROM InitialLog
GROUP BY MDid
This aggregating subquery yields one row per doctor, with the very last day of the first month in it. (That's what MIN(LAST_DAY(DateLastSaved)) does.)
Pro tip: many people find it helpful to test their subqueries in phpMyAdmin or some other command line SQL program.
Let us now use it in another subquery to find the latest date that occurs in that first month in the table.
SELECT MAX(DateLastSaved) LastInMonth,
a.MDid
FROM InitialLog a
JOIN (
SELECT MDid, MIN(LAST_DAY(DateLastSaved)) FirstMonth
FROM InitialLog
GROUP BY MDid
) b ON a.MDid = b.MDid
AND LAST_DAY(a.DateLastSaved) = b.FirstMonth
GROUP BY a.MDid
Here we join the InitialLog table to the first subquery, using the ON clause to eliminate all the rows of InitialLog that aren't in the first month (that's what LAST_DAY(a.DateLastSaved) = b.FirstMonth does).
Cool. this subquery gives us the date in your specification for each doctor. Finally, we have to go get the original row, containing the FileName as well as the other columns. We already know the MDid and the DateLastSaved.
This is the final query.
SELECT orig.DateLastSaved, orig.MDid, orig.FileName
FROM InitialLog orig
JOIN ( /* that subquery */
) datechoice ON orig.MDid = datechoice.MDid
AND orig.DateLastSaved = datechoice.LastInMonth
ORDER BY orig.MDid /* or whatever order you want */
This gives one row per MDid. It uses the DBMS to implement your specification, rather than looking at all the rows of your table. If your table has an index on (MDid, DateLastSaved) this query will probably scale up very well when you have tens of thousands of doctors and decades of data in your table.
Putting it all together, your php program is this. Now you may be able to guess why it's called Structured Query language.
$docs_first_monthend_bill_query = <<<ENDQUERY
SELECT orig.DateLastSaved, orig.MDid, orig.FileName
FROM InitialLog orig
JOIN (
SELECT MAX(DateLastSaved) LastInMonth,
a.MDid
FROM InitialLog a
JOIN (
SELECT MDid, MIN(LAST_DAY(DateLastSaved)) FirstMonth
FROM InitialLog
GROUP BY MDid
) b ON a.MDid = b.MDid
AND LAST_DAY(a.DateLastSaved) = b.FirstMonth
GROUP BY a.MDid
) datechoice ON orig.MDid = datechoice.MDid
AND orig.DateLastSaved = datechoice.LastInMonth
ORDER BY orig.MDid /* or whatever order you want */
ENDQUERY;
$result=$db->query($docs_first_monthend_bill_query);
while($row3=mysqli_fetch_array($result)) {
/* process the interesting rows */
}
You can reduce the page loading time by using LIMIT in query and fetch result with pagination. So the all records will not come in a single result set but that can be possible via paging
SELECT DateLastSaved,MDid,FileName FROM InitialLog WHERE FileName NOT LIKE '%Patient Names%' LIMIT $offset $perpage
Here $offset is the index number of your results (page_number * $perpage) and $perpage is the how much rows you want to fetch in a single query.
On first thought i would say you are trying to get the most recent 'DateLastSaved' for each 'MDid' and 'FileName' combination.
If so, i would simply alter the SQL to
SELECT concat(MDid, FileName) tobestored,
max(DateLastSaved) maxDateLastSaved
FROM InitialLog
GROUP BY 1
This query would return only one row per 'MDid' and 'FileName' combination containing the combined value and the most recent date.
No more need to loop through all fetched records to search arraykeys or compare dates.
The only thing that i am not sure about is this part
if($aryear==$pryear && $armonth==$prmonth) {
if($prday>$arday) {
$datearray[$key]=$date;
}
}
Looks like you want to keep the older 'DateLastSaved' if it is from a previous month or year.
If this applies, my change to your query does not give your desired data.

MySQL rollup with Pearson's R

I'm using MySQL & PHP to calculate Pearson's R measuring the relationship over a number of years between political donations and tenders received by a particular business.
I've run into trouble with the MySQL query that is feeding values into the algorithm. The algorithm itself is fine and evaluates correctly. The problem is in the query used to get the data.
The formula I'm using for Pearson's R is at http://www.statisticshowto.com/how-to-compute-pearsons-correlation-coefficients/
Here is the basic MySQL query that spits out values for each year:
SELECT count( distinct year) as count,name,sum(donations), sum(tenders), sum(donations * tenders) as xy,(sum(donations)*sum(donations)) as x2, (sum(tenders)*sum(tenders)) as y2 from money_by_year where name='$name' group by name,year
Here is the query WITH ROLLUP to get only the final values:
SELECT count( distinct year) as count,name,sum(donations), sum(tenders), sum(donations * tenders) as xy,(sum(donations)*sum(donations)) as x2, (sum(tenders)*sum(tenders)) as y2 from money_by_year where name='$name' group by name with rollup LIMIT 1
The problem is that the totals from the second query are wrong in the sum xy, x2 & y2. This is being caused by the query itself, probably the ROLLUP and I'd like to know what is going on with it.
You can see working examples of the code with the values resulting from both the above queries and the algorithm at https://openaus.net.au/follow_the_money.php?name=KPMG
I have tried various changes to sum(donations * tenders) as xy for example implementing it as sum(donations) * sum(tenders) as in:
SELECT count( distinct year) as count,name,sum(donations), sum(tenders), sum(donations) * sum(tenders) as xy,(sum(donations)*sum(donations)) as x2, (sum(tenders)*sum(tenders)) as y2 from money_by_year where name='KPMG' group by name with rollup LIMIT 1
however the ROLLUP totals are incorrect, much bigger than they should be. The values I want may not be possible via a single MySQL query however I would appreciate knowing why this is the case, what the ROLLUP is doing to the figures and why.

Select Data Based on Column Less Than Current Date and Empty Columns

For example, i have two tables like this
Table User:
Table Payment:
I want to join two table above, but i want to get the result as quantity,
How many of blanks price columns based from previous of current date.
So if current date is 2015-04-10, the result will be look like this:
I don't have any clue how to do that using some syntax query combination in SQL or in PHP to display the result
In SQL, you could do something like this:
SELECT user_name, COUNT(name) AS result
FROM user
JOIN payment ON users.id = payment.id_user
WHERE (price IS NULL OR ltrim(price) = '')
AND payments.last_pay < '2015-04-10'
GROUP BY payment.id_user
You can see the result of this query in the SQL Fiddle.

MySQL select between two dates not working as expected

I'm trying to create a query that will select all dates between two dates
This is my query:
$query = "SELECT DISTINCT * FROM D1,D2
WHERE D1.DATE_ADDED BETWEEN '$date1' AND '$date2' AND D1.D1_ID = D2.D2_ID";
The trouble is, it is not returning anything, but not producing an error either
So I tried inputting it directly into phpMyAdmin like this
SELECT DISTINCT * FROM D1,D2
WHERE D1.DATE_ADDED BETWEEN '2011-01-01' AND '2011-12-12'
AND D1.D1_ID = D2.D2_ID`
then like this
SELECT DISTINCT * FROM D1,D2
WHERE D1.DATE_ADDED BETWEEN '2011-01-01' AND '2011-12-12'
and like this
SELECT * FROM D1
WHERE DATE_ADDED BETWEEN '2011-01-01' AND '2011-12-12'
and I just get
MySQL returned an empty result set (i.e. zero rows). ( Query took 0.0003 sec )
Yes, my tables exist, and so do the columns :)
In the first cases the lack of results could be because of the inner join. For a result to be in the set it would require a record in both tables, ie. a record from d1 would not appear unless d2 also had that id in the d2_id column. To resolve this, if that is correct for your business logic, use left join.
However, the last of your cases (without the join) suggests the reasons is a lack of matching records in the first (left) table d1.
Without the full dataset we can't really comment further, since all the code you are running is perfectly valid.
If you always want to select an entire year it is easer to select it like this:
SELECT * FROM D1 WHERE YEAR(DATE_ADDED) = 2011;
Please implement below code
SELECT DISTINCT * FROM D1,D2
WHERE D1.DATE_ADDED BETWEEN DATE_FORMAT('2011-01-01','%Y-%m-%d')
AND DATE_FORMAT('2011-12-12','%Y-%m-%d')
AND D1.D1_ID = D2.D2_ID`

Categories