1

I am trying to select data from mysql by a date field in the database. (Users can enter start date and end date)

For each selected row between user selected dates, I need to select from the same table to produce a result.

Example:

    $query = "SELECT * FROM table WHERE date BETWEEN $begindate AND $enddate"; //Select by date
    $result = mysqli_query($dbc,$query);
    while($row = mysqli_fetch_array($result)){
        vardump($row); //user needs to see all data between date selection
        $query = "SELECT * FROM table WHERE field = $row['field']";
        // and then do calculations with the data
    }

This runs very slowly and I can see why. How can I improve the run speed?

Edit: The original purpose was to generate a sales report between dates. Now the user wants the report to produce another result. This result could only be produced by searching against the same table, and the rows that I need is not within the date selection.

Edit 2: I do need to output the entire table between date selection. Each row will need to find ALL other rows where field = field, within or out side of the date selection.

Edit 3: Solved the problem. All the answers are helpful, though I think the chosen answer was most related to my question. However, I believe using join when working with two tables is the right way to go. For my problem, I actually just solved it by duplicating the table and run my search against the duplicated table. The chosen answer did not work for me because the second query selection is not a part of the first query selection. Hope this would help anyone looking at this post. Again, thanks for all the help!

PenPen
  • 58
  • 5
  • 4
    Do you have any indexes on your table? – Mark Baker Dec 12 '17 at 15:44
  • 1
    And why are you running a loop of individual queries against table? – Mark Baker Dec 12 '17 at 15:45
  • A query inside a loop of the results of another query tends to perform badly, as you land up with a massive number of queries. Hence using JOINs most of the time. – Kickstart Dec 12 '17 at 15:46
  • 1
    Look into the JOIN syntax in SQL so you can run ONE query to get all the data in one execution. I am assuming that you are looking at two different tables here right? – RiggsFolly Dec 12 '17 at 15:47
  • 1
    use meaningfull names for table and field. Is the same table on both queries? – Juan Carlos Oropeza Dec 12 '17 at 15:54
  • @MarkBaker Yes, I do have index on table. – PenPen Dec 12 '17 at 16:04
  • Any old index, or an actually useful index, on columns that you reference in the where clauses of your queries? Show us your real table structures and the indexes that you have on those tables – Mark Baker Dec 12 '17 at 16:07
  • @JuanCarlosOropeza Yes, same table both queries. And one is not a sub-set of the other. – PenPen Dec 12 '17 at 16:37
  • 1
    The answer by Codemole should do what you need to do without any need to duplicate the table. Although the join suggested by Tony Chiboucas should also work and would be my choice. Not a problem doing a self join and returning the data from both the matching rows. – Kickstart Dec 13 '17 at 08:25

3 Answers3

2

Well, so if you are really looking for such a conditions in same table, I suggest you should use IN selector like following:

$query = "SELECT * FROM table 
           WHERE field IN 
               (SELECT DISTINCT field FROM table 
                WHERE 
                    date BETWEEN $begindate AND $enddate)";

So final code will look some like following:

    $query = "SELECT * FROM table 
           WHERE field IN 
               (SELECT DISTINCT field FROM table 
                WHERE 
                    date BETWEEN $begindate AND $enddate)";
    $result = mysqli_query($dbc,$query);
    while($row = mysqli_fetch_array($result)){
        // do calculations with the $row
    }
Codemole
  • 3,069
  • 5
  • 25
  • 41
  • You can do joins even if OP is using the same table – RiggsFolly Dec 12 '17 at 16:12
  • @RiggsFolly please explain. It might be what I am looking for. – PenPen Dec 12 '17 at 16:34
  • 1
    I would offer to simplify inner query to just SELECT DISTINCT and remove group by.. same result, but easier clarification to a single record per "field". Good answer and would just close with the outer query doing an order by the field, then the date possibly descending so the PHP output does not have to then sort data. Good answer though. – DRapp Dec 12 '17 at 16:45
  • @RiggsFolly because of being one table, depends on table data, joining wont be a good option. Especially when field has many same data in it, joining might simply run slow. – Codemole Dec 12 '17 at 18:27
  • @PenPen I believe this answer will be the right one you are looking for. – Codemole Dec 12 '17 at 18:27
  • @DRapp Thanks for your kind and valuable option. I am gonna adopt distinct. – Codemole Dec 12 '17 at 18:28
  • @Codemole Thanks for the help. Your answer eventually helped me to solve the problem. The part that didn't work was that I am not selecting field in between the dates, but search against the whole table again. Thanks again for the help though! – PenPen Dec 12 '17 at 19:38
1

I guess your table names arent TABLE:

just user inner join

 $query = "SELECT * 
           FROM table1
           JOIN table2 
             ON table1.field = table2.field
           WHERE date BETWEEN $begindate AND $enddate
           ORDER BY table1.field;"
Juan Carlos Oropeza
  • 47,252
  • 12
  • 78
  • 118
0

Stop writing pseudo-SQL

SELECT * FROM is technically pseudo-SQL (a sql command which the interpreter has to modify before the command can be executed. It is best to get in a habit of specifying columns in the SELECT statement.

Use SQL joins

Joins are what makes relational databases so useful, and powerful. Learn them. Love them.

Your set of SQL queries, combined into a single query:

SELECT 
    table1.id as Aid, table1.name as Aname, table1.field as Afield,
    table2.id as Bid, table2.name as Bname, table2.field 
FROM table table1
LEFT JOIN table table2 
    ON table1.field = table2.field
WHERE table1.date BETWEEN $begindate AND $enddate
ORDER BY table1.id, table2.id

Your resulting print of the data should result in something which access each set of data akin to:

$previous_table1_id = 0;
while($row = mysqli_fetch_array($result)){
    if ($row['Aid'] != $previous_table1_id) {
        echo 'Table1: ' . $row['Aid'] . ' - ' . $row['Aname'] . ' - '. $row['Afield'] . "\n";
        $previous_table1_id = $row['Aid'];
    }

    echo 'Table2: ' . $row['Bid'] . ' - ' . $row['Bname'];
}

Dealing with aggregated data

Data-aggregation (multiple matches for table1/table2 on field), is a complex subject, but important to get to know. For now, I'll leave you with this:

What follows is a simplified example of one of what aggregated data is, and one of the myriad approaches to working with it.

Contents of Table
id |  name  |  field
--------------------
1  |  foos  |  whoag 
2  |  doh   |  whoag
3  |  rah   |  whoag
4  |  fun   |  wat
5  |  ish   |  wat

Result of query I gave you
Aid | Aname | Afield | Bid | Bname
----------------------------------
1   | foos  | whoag  | 1   | foos
1   | foos  | whoag  | 2   | doh
1   | foos  | whoag  | 3   | rah
2   | doh   | whoag  | 1   | foos
2   | doh   | whoag  | 2   | doh
2   | doh   | whoag  | 3   | rah
3   | rah   | whoag  | 1   | foos
3   | rah   | whoag  | 2   | doh
3   | rah   | whoag  | 3   | rah
4   | fun   | wat    | 4   | fun
4   | fun   | wat    | 5   | ish
5   | ish   | wat    | 4   | fun
5   | ish   | wat    | 5   | ish

GROUP BY example of shrinking result set

    SELECT table1.id as Aid, table1.name as Aname
           group_concat(table2.name) as field
    FROM table table1
    LEFT JOIN table table2 
        ON table1.field = table2.field
    WHERE table1.date BETWEEN $begindate AND $enddate
    ORDER BY table1.id, table2.id
    GROUP BY Aid

Aid | Aname | field
----------------------------------
1   | foos  | foos,doh,rah
2   | doh   | foos,doh,rah
3   | rah   | foos,doh,rah
4   | fun   | fun, ish
5   | ish   | fun, ish
Tony Chiboucas
  • 5,505
  • 1
  • 29
  • 37
  • Thanks for help! I am not working with two tables. I need to search against the table itself. – PenPen Dec 12 '17 at 16:34
  • @PenPen, that's what this join does. Join the table against itself. `From table table1` creates an "alias" for your "table". This is how self-joins are completed. You can try yourself with a simple query: `SELECT DISTINCT(a.field) as Afield FROM table a;` – Tony Chiboucas Dec 12 '17 at 20:20
  • @PenPen, please just try plugging this into your PhpMyAdmin, or MySql console: `SELECT a.*, b.* FROM table a LEFT JOIN table b ON a.field = b.field`. Then you can at least see the data you're working with. – Tony Chiboucas Dec 13 '17 at 15:46