SELECT DISTINCT with other colum - php

I got a question.
I have following mysql table:
domain | visited
domain1.net | 21.02.2019 - 18:55
domain1.net | 20.02.2019 - 14:01
domain1.net | 22.02.2019 - 12:05
domain2.net | 24.02.2019 - 19:01
domain2.net | 22.02.2019 - 17:21
I want following result:
domain1.net | 22.02.2019 - 12:05
domain2.net | 24.02.2019 - 19:01
No duplicate domain and the latest visited.
My code:
<?php
$sql = "SELECT DISTINCT p_domain FROM table_content";
$result = $db->prepare($sql);
$result->execute();
while ($row = $result->fetch()) {
$domain = $row['domain'];
echo "<tr>"
. "<td>$domain</td>"
. "</tr>";
}
?>

You can use your domain DISTINCT with your column, to get the latest visited domain you can use Order by
SELECT DISTINCT domain FROM table_content Order By visited DESC
ORDER BY: Order by clause is used to sort the data in ascending or descending order.
DISTINCT: The SELECT DISTINCT statement is used to retrieve only distinct (different) values from the database.

You use GROUP BY:
SELECT p_domain, MAX(visited) as most_recent_visit
FROM table_content
GROUP BY p_domain
Group by establishes a list of columns that you want the unique combinations of. Other columns in your select that are not in the group by list do not form a unique grouping key and MUST be expressed as some form of aggregation:
SELECT ethnicity, city, AVG(age), COUNT(*), SUM(number_of_cars_owned), MIN(birthdate), MAX(number_of_children)
FROM person_table
GROUP BY ethnicity, city
This gets the average age, total count, the total of cars owned, the oldest person, the largest family per ethnic group per city
It is important to note that the values for the aggregates come from different rows (in the Chicago Caucasian category, the Smith family might have the most children but the Doe family has the oldest person), and might not be present in the rows at all (the average age might be 27.32615).
A common query is like "I want to find the earliest date someone visited each of my sites and what their ip address was" - that is a site, min(visitdate) group by site but you can't just bang the IP address in there too, either as a grouped thing site, ipaddress min(visitdate) group by site, ipaddress because that is "the first visit per site per ip" and you can't whack the ip into an aggregating function site, min(visitdate), min(ipaddress) group by site because the min ip may come from a different row to the min date.
If you want the site, the first visit date and the ip of that visit you have to run the aggregate as a subquery and join it back to the main table to get the other data from the row with the min date
select *
from
(select site, min(visitdate) min_d from t group by site) x
inner join t on t.site = x.site and t.visitdate = x.min_d
ps: the comment makes a really good point; if your visited date isn't a date but instead a string-that-looks-like-a-date-to-you then getting the MAX() of it will not necessarily return the most recent date, it will return the alphabetically latest date. You should definitely store dates using the proper date/time data types so that functions like MAX can work properly. If you haven't done this please change things so it is done like this.. because writing a query that parses millions of strings into dates every time it is run, just so that max will work properly, is a huge waste of resources.

Related

count total no of visits based on date codeigniter

Аctually I am working on the CI medical project. I have column name visit date. I want to display the total no of visits by each patient on that specific date, for example 5-4-2019 total visits by that patient were 3. Similarly 4-3-2020 total visits were 5.
How can I create another column that counts total visits based on this column visit date?
Since you have provided no DDL or DML, the best we can do is guess at what your schema might be and what your code might look like. So, here's a guess:
select -- <your existing columns>
visits_on_this_date = count(*) over (partition by patient_id, visit_date)
from -- the rest of your query here
Something simple like that?
select patient_id,visit_date,count(*) as total_visits
from table
group by patient_id,visit_date

How do I improve the speed of these PHP MySQLi queries without indexing?

Lets start by saying that I cant use INDEXING as I need the INSERT, DELETE and UPDATE for this table to be super fast, which they are.
I have a page that displays a summary of order units collected in a database table. To populate the table an order number is created and then individual units associated with that order are scanned into the table to recored which units are associated with each order.
For the purposes of this example the table has the following columns.
id, UID, order, originator, receiver, datetime
The individual unit quantities can be in the 1000's per order and the entire table is growing to hundreds of thousands of units.
The summary page displays the number of units per order and the first and last unit number for each order. I limit the number of orders to be displayed to the last 30 order numbers.
For example:
Order 10 has 200 units. first UID 1510 last UID 1756
Order 11 has 300 units. first UID 1922 last UID 2831
..........
..........
Currently the response time for the query is about 3 seconds as the code performs the following:
Look up the last 30 orders by by id and sort by order number
While looking at each order number in the array
-- Count the number of database rows that have that order number
-- Select the first UID from all the rows as first
-- Select the last UID from all the rows as last
Display the result
I've determined the majority of the time is taken by the Count of the number of units in each order ~1.8 seconds and then determining the first and last numbers in each order ~1 second.
I am really interested in if there is a way to speed up these queries without INDEXING. Here is the code with the queries.
First request selects the last 30 orders processed selected by id and grouped by order number. This gives the last 30 unique order numbers.
$result = mysqli_query($con, "SELECT order, ANY_VALUE(receiver) AS receiver, ANY_VALUE(originator) AS originator, ANY_VALUE(id) AS id
FROM scandb
GROUP BY order
ORDER BY id
DESC LIMIT 30");
While fetching the last 30 order numbers count the number of units and the first and last UID for each order.
while($row=mysqli_fetch_array($result)){
$count = mysqli_fetch_array(mysqli_query($con, "SELECT order, COUNT(*) as count FROM scandb WHERE order ='".$row['order']."' "));
$firstLast = mysqli_fetch_array(mysqli_query($con, "SELECT (SELECT UID FROM scandb WHERE orderNumber ='".$row['order']."' ORDER BY UID LIMIT 1) as 'first', (SELECT UID FROM barcode WHERE order ='".$row['order']."' ORDER BY UID DESC LIMIT 1) as 'last'"));
echo "<td align= center>".$count['count']."</td>";
echo "<td align= center>".$firstLast['first']."</td>";
echo "<td align= center>".$firstLast['last']."</td>";
}
With 100K lines in the database this whole query is taking about 3 seconds. The majority of the time is in the $count and $firstlast queries. I'd like to know if there is a more efficient way to get this same data in a faster time without Indexing the table. Any special tricks that anyone has would be greatly appreciated.
Design your database with caution
This first tip may seems obvious, but the fact is that most database problems come from badly-designed table structure.
For example, I have seen people storing information such as client info and payment info in the same database column. For both the database system and developers who will have to work on it, this is not a good thing.
When creating a database, always put information on various tables, use clear naming standards and make use of primary keys.
Know what you should optimize
If you want to optimize a specific query, it is extremely useful to be able to get an in-depth look at the result of a query. Using the EXPLAIN statement, you will get lots of useful info on the result produced by a specific query, as shown in the example below:
EXPLAIN SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column;
Don’t select what you don’t need
A very common way to get the desired data is to use the * symbol, which will get all fields from the desired table:
SELECT * FROM wp_posts;
Instead, you should definitely select only the desired fields as shown in the example below. On a very small site with, let’s say, one visitor per minute, that wouldn’t make a difference. But on a site such as Cats Who Code, it saves a lot of work for the database.
SELECT title, excerpt, author FROM wp_posts;
Avoid queries in loops
When using SQL along with a programming language such as PHP, it can be tempting to use SQL queries inside a loop. But doing so is like hammering your database with queries.
This example illustrates the whole “queries in loops” problem:
foreach ($display_order as $id => $ordinal) {
$sql = "UPDATE categories SET display_order = $ordinal WHERE id = $id";
mysql_query($sql);
}
Here is what you should do instead:
UPDATE categories
SET display_order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END
WHERE id IN (1,2,3)
Use join instead of subqueries
As a programmer, subqueries are something that you can be tempted to use and abuse. Subqueries, as show below, can be very useful:
SELECT a.id,
(SELECT MAX(created)
FROM posts
WHERE author_id = a.id)
AS latest_post FROM authors a
Although subqueries are useful, they often can be replaced by a join, which is definitely faster to execute.
SELECT a.id, MAX(p.created) AS latest_post
FROM authors a
INNER JOIN posts p
ON (a.id = p.author_id)
GROUP BY a.id
Source: http://20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck/

Trouble combining Two sql queries into one

I have a table which contains due dates for individual member records. Each row contains four fields:
ID | Next_Due | Next_Due_Missed | Amount
=============================================================
123 | 2010-12-05 | NULL | 41.32
456 | 2010-12-10 | 2010-12-05 | 21.44
789 | 2010-12-20 | 2010-12-10 | 39.99
ID is the unique id of each MEMBER
Next Due - is the next due day of their regular subscription period
Next_Due_Missed is populated ONLY if there was an error collecting the first round of subscription payment.
Amount is amount owned for subscription.
My goal is to create a sql query that checks if next_due_missed exists and is not null. If it does, use that value as the '$date'. If not, set $date = value of next_due
this is done easily enough except my results are grouped by Next_Due in normal circumstances and will omit next_due_missed if I combine the way I currently am.
Every payment period, there may be 600+ records with next_due equal to the desired date (and 10-15 equal to next_due_missed).
My current query is:
$stmt = $db->prepare("SELECT next_due, next_due_missed FROM table_name WHERE (next_due > CURDATE() OR next_due_missed > CURDATE()) GROUP BY next_due ASC");
This only returns results for next_due however. Omitting the GROUP BY clause returns hundreds of results (while I need to group in this stage).
Similarly at a later point, I will need to break out those individual records and actually create payment records based on the 'next_due' and 'next_due_missed' values.
Any ideas what I am missing?
I am not sure the purpose of your GROUP BY other than to get DISTINCT values, but left it in in case you provided a partial query:
SELECT coalesce(next_due_missed, next_due) as EffectiveNextDue
FROM table_name
WHERE coalesce(next_due_missed, next_due) > CURDATE()
GROUP BY coalesce(next_due_missed, next_due)

Semi-Complicated PHP/MySQL Select Statement

I currently have 3 tables, which I'm using for people to make reservations for certain pieces of equipment.
Here are my tables:
tblEquipment:
id name description
1 Camera Takes pictures
2 Projector Projects pictures
3 Laptop Portable Computer
tblEvents:
id start end first_name last_name email
1 2009-08-10 2009-08-11 John Doe jd#email.com
2 2009-08-15 2009-08-16 Jane Doe jd#email.com
tblEventData:
id eventID equipmentID
1 1 1
2 1 2
Right now, a user will submit a query with their requested times, then they will see all available equipment.
So, using the exampe above, if a user is looking for equipment between 8/10-8/11, he will see that the only equipment that is available is: equipmentID 3 (Laptop).
How can I create my query to return only the available equipment based on the requested times?
This is what I've come up with so far, but can't get it to work:
SELECT tblequipment.id as name, tblEvents.start as start, tblEvents.end as end
FROM tblEquipment
INNER JOIN tblEventData on tblEventData.equipmentID = tblEquipment.id
INNER JOIN tblEvents on tbleventdata.eventID = tblEvents.id
WHERE NOT EXISTS(SELECT * FROM tblEvents WHERE $end >= start AND $start <= end)
Any ideas? Thanks!
The query you have now has a NOT EXISTS looking only for events that occur between the start and end times given. In other words, "select all equipment as long as there are no events in this timeframe." That's not what you want. You want: "select all equipment as long as there are no events using that equipment in this timeframe."
That translates to something like:
SELECT tblequipment.id as name
FROM tblEquipment
WHERE NOT EXISTS
(SELECT * FROM tblEvents
INNER JOIN tblEventData ON (tblEvents.id = tblEventData.eventID)
WHERE $end >= start AND $start <= end
AND tblEventData.equipmentID = tblEquipment.id)
EDIT: I've also removed the JOINs from the outer query, since they insist that you select only equipment that's reserved at some point, which is not at all relevant to the question you're trying to answer.
You do want to know what equipment is reserved, but inside the NOT EXISTS query, for the purposes of excluding it from your final results.
Try putting end in quotes so it is
`end`
I think mysql is interpreting end as a command rather than a field.
"end" is a reserved word in SQL. Try naming tblEvents.end something else.

mysql - search between dates where all dates appear

I'm working with some imported data that stores details about whether a "room" is available on a specific day or not. Each room has an individual entry for the date that it is available.
| id | date | price |
--------------------------------
| 1 | 2010-08-04 | 45.00 |
A user can search across a date range and the search needs to bring back the relevant rooms that are available between those two dates.
In other words using a sql query to search:
where date>=2010-08-04 AND date<=2010-08-09
would not suffice as this would bring back all rooms available at SOME point between the chosen dates not the rooms that are available for ALL of the dates concerned.
I am considering using a temporary date table in some way to cross-reference that there is an entry for every date in the range but are uncertain as to the best way to implement this.
The end code platform is PHP and I'm also exploring whether the data can be processed subsequently within the code but would like to keep everything with the sql if possible.
Any suggestions that put forward would be greatly appreciated.
Thanks
Update: my original answer was identical to Quassnoi's but 1 minute too late, so I decided to delete it and do something different instead. This query does not assume that (id, date) is unique. If there is more than one entry, it selects the cheapest. Also, it also sums the total cost and returns that too which might also be useful.
SELECT id, SUM(price) FROM (
SELECT id, date, MIN(price) AS price
FROM Table1
GROUP BY id, date) AS T1
WHERE `date` BETWEEN '2010-08-05' AND '2010-08-07'
GROUP BY id
HAVING COUNT(*) = DATEDIFF('2010-08-07','2010-08-05') + 1
Provided that (id, date) combination is unique:
SELECT id
FROM mytable
WHERE date BETWEEN '2010-08-04' AND '2010-08-09'
GROUP BY
id
HAVING COUNT(*) = DATEDIFF('2010-08-09', '2010-08-04') + 1
Make sure you have a UNIQUE constraint on (id, date) and the date is stored as DATE, not DATETIME.

Categories