Get rows matching all items from an array - php

I can do it with a loop or an alternate solution, but this would mean time consuming (on page loading).... So I would like to know if there is a 'one query' solution.
I have a table containing 4 columns:
id class day hour
1 9b3 1 3
2 9b4 1 3
3 9b5 1 3
4 9b3 1 5
5 9b4 2 6
6 9b5 2 6
7 9b4 4 7
8 9b3 3 6
9 9b4 3 6
10 9b5 3 6
What I need is to recover the day and hour matching all three classes 9b3, 9b4, 9b5 at the same day and hour.
In the example above, the result should be:
day hour
1 3
3 6

Try this:
SELECT day,hour
FROM yourTableName
WHERE class IN ('9b3','9b4','9b5')
GROUP BY day,hour
HAVING COUNT(class) = 3;
sqlfiddle demo

also that works...
SELECT day,hour
FROM Table1
WHERE (class = '9b3' or class = '9b4' or class = '9b5')
GROUP BY day,hour
HAVING COUNT(class) = 3;

SELECT day,hour FROM table
WHERE class IN('9b3','9b4','9b5')GROUP BY day HAVING COUNT(class)=3;

This can be achieved simple by using SQL statement syntax depending on the action that you want to perform. Picking the raw data can be done like this:
SELECT * FROM YourTable
WHERE day='1' and hour='3'

Related

MySQL querying date range

Here's my database (free rooms in a hotel, simplified)
rooms_available:
id date_available room_id
================================
1 2013-12-19 2
2 2013-12-20 2
3 2013-12-21 2
4 2013-12-22 2
5 2013-12-23 2
6 2013-12-25 3
rooms:
id name minimal_range
================================
2 Apartment A 5
3 Apartment B 1
I want to query all rooms which are available between 2013-12-20 and 2013-12-22
My query is like:
select *
from rooms_available
where (date='2013-12-20' OR date='2013-12-21' OR date='2013-12-22')
My questions:
is there a more comfortable way? when the date range will be like 2 weeks, the query will also be very long (which will take much longer for querying)
would it be possible to consider minimum ranges - for example: room_id 2 is only available for at least 5 nights (see table "rooms") -> so above query should return no records
Thanks
date >= '2013-12-20' and date <= '2013-12-22'
SELECT * FROM rooms_available WHERE `date_available` BETWEEN "2013-12-20 " AND "2012-03-31"
I didn't test this but it should point you in the right direction especially for the second part of your question about minimal range.
SELECT t1.id as id, t1.date_available as date_available, t1.room_id
FROM rooms_availble as t1 JOIN rooms as t2 on t1.room_id = t2.id
WHERE t1.date_available BETWEEN DATE('2013-12-20') AND DATE('2012-03-31') AND
t2.minimal_range <= datediff('2013-12-22', '2012-12-20');
The mysql datediff function will return the number of days between two dates then you can just compare it with the minimal_range from the rooms join table. Also you might consider binding the start and end dates to variables so that you only have to write each date once.

ordering two columns php mysql

I have a query:
<?php
$results = $dbConn->select("SELECT entryA, entryB FROM table");
/**
Displays the rows on $results (entryA, entryB)
1 7
8 5
4 3
5 8
7 1
3 4
**/
$results = $dbConn->select("SELECT entryA, entryB FROM table ORDER BY ?");
/**
The correct output must be: (entryA, entryB)
1 7
7 1
8 5
5 8
4 3
**/
?>
How can i possible to order two columns that equal/match to each other ids in a different row?
Thanks in advance.
Yes, it is. For example
SELECT entryA, entryB FROM table ORDER BY entryA*entryA+entryB*entryB
-in my samples I'm supposing you have both pair variants, i,e {1,7} and {7,1}, for example.
This will group same pairs independent of elements order, but you may wish to have additional order condition - then simply add it to ORDER BY clause

Inserting new entry and updating a whole column at the same time

I have a somewhat complex problem that needs fixing, for now I have the following table structure (task_schedule):
id taskid productid product_position
1 1 1 1
2 2 1 2
3 3 2 1
4 4 1 3
5 5 2 2
6 6 3 1
product_position works the following way: it should look at the productid and increment from the previous max value entry.
I accomplish this with the following query (probably easier to understand too):
INSERT into task_schedule (taskid, productid, product_position)
SELECT 1,1, max(product_position) + 1
FROM task_schedule
WHERE productid=1
(the values are of course attributed in the php backend)
I need a new column now though. Lets call it user_position, I'm going to recreate my table with an example:
id taskid productid product_position user_position
1 1 1 1 1
2 2 1 2 4
3 3 2 1 2
4 4 1 3 6
5 5 2 2 5
6 6 3 1 3
OK, so how this should work is: user_position should individually run through each entry and look at the productid, it should build a position list based on an even order of priority.
So if I ordered this by user_position I would get the following entry id list: 1 3 6 2 5 4
An example of what I need done in php:
Imagine the following list: red red red green green green green blue blue yellow
$array1 = array(array("red"), array("red"), array("red"));
$array2 = array(array("green"), array("green"), array("green"), array("green"));
$array3 = array(array("blue"), array("blue"));
$array4 = array(array("yellow"));
$Arrays= array ($array1, $array2, $array3, $array4);
foreach ($Arrays as $type => $list) {
$ArrayLength[]=count($list);
}
$MergeArray=array();
$flag=true;
for($i=0;$flag==true;$i++)
{
$flag=false;
for($j=0;$j < count($ArrayLength);$j++)
{
if( $i < $ArrayLength[$j] )
{
array_push( $MergeArray , $Arrays[$j][$i] );
$flag=true;
}
}
}
echo "<pre>".Print_r(json_encode($MergeArray), true)."</pre>";
This returns me a consistent list with the pattern I desire:
[["red"],["green"],["blue"],["yellow"],["red"],["green"],["blue"],["red"],["green"],["green"]]
All of the above is just an example of what I need, but implemented via MySQL.
I don't even know how to approach this issue now though, I need a way to insert new entries AND update the user_position column accordingly.
If I was to add a new entry into my table, with a new peoduct_id, this should be the end result:
id taskid productid product_position user_position
1 1 1 1 1
2 2 1 2 5
3 3 2 1 2
4 4 1 3 7
5 5 2 2 6
6 6 3 1 3
7 7 4 1 4
Notice how the user_position shifted to accommodate the new row.
I think this is a fairly complex problem to solve (or maybe my mysql is just THAT weak), I don't think there is a easy solution for this one, so any input you might have on how to approach this via mysql (mysql doing the heavy lifting would be fantastic), but I welcome a PHP solution as well with multiple queries and whatnot. Unfortunately I can't drop this column, it's easy to grab entries and let PHP sort my information, but I really need this implemented in the database.
Any input from the community would be great really.
Insert using the normal insert query which you are using
INSERT into task_schedule (taskid, productid, product_position, user_position)
SELECT 1,1, max(product_position) + 1, 0 FROM task_schedule WHERE productid=1;
And then update all the entries based on product_position using the below
SET #counter = 0;
UPDATE task_schedule SET user_position = #counter := #counter + 1 ORDER BY product_position asc, productid asc;
Here is the SQL fiddle link

Count the number of rows in SQL using a string as criteria

I have the string $niveis with the following values (example):
3,8,10
Using this string, I need to count the number of rows in table content, where the access matches any of these 3 values.
For example, if table content is:
id access
1 2
2 3
3 3
4 7
5 8
6 9
7 10
8 10
Should return 5.
I tried the following query in PHP:
$query="SELECT count(id) FROM #__content WHERE access =$niveis";
But it isn't working, can anyone help?
You can use IN keyword
SELECT COUNT(id)
FROM #__content
WHERE access IN ($niveis)
You can use find_in_set():
select count(id)
from #__content
where find_in_set(access, $niveis) > 0;

How do I efficiently find and keep a log of duplicate tweets in my database?

Please consider the following "tweets" table:
tweet_id user_id text
----------------------------
1 1 lorem ipsum
2 1 lorem ipsum
3 2 pear
4 1 dolor
5 3 foo
6 1 dolor
7 1 dolor
8 3 bar
9 3 baz
10 4 happy
11 4 happy
12 2 apple
13 3 foo
14 4 happy
In reality, the table contains millions of tweets from about 80,000 users. Many of there users are spam accounts, but they are hard to identify by hand. As a rule of thumb, spam accounts post the same message at least 3 times. That's why I want to fill the following tables, "duplicates" on the left and "duplicates_tweets" on the right:
duplicate_id user_id text cnt duplicate_id tweet_id
-------------------------------------- ----------------------
1 1 lorem ipsum 2 1 1
2 1 dolor 3 1 2
3 2 pear 1 2 4
4 2 apple 1 2 6
5 3 foo 2 2 7
6 3 bar 1 3 3
7 3 baz 1 4 12
8 4 happy 3 5 5
5 13
6 8
7 9
8 10
8 11
8 14
I can now very easily sort on cnt for instance, and see which users post the most duplicate messages. My question however, is how to go about this most efficiently. In other words: what query would be most efficient to fill these tables? And is it possible with just SQL or should I use PHP as an intermediary, for instance to take a tweet from the "tweets" database, scans for duplicates, fills the tables, and moves on to the next tweet? I'm afraid this would take ages to finish, so any help is greatly appreciated!
Probably, you could sort the table "tweets" by user_id and then by text:
SELECT * FROM tweets ORDER BY user_id DESC, text DESC
Afterwards you can iterate over the results in PHP:
<?php
// ...
$lastuser = -1;
$lasttext = "";
$ids = array();
while ($row = mysql_fetch_assoc($result)) {
if($row['user_id'] != $lastuser || $row['text'] != $lasttext) {
$ids = array();
}
$ids[] = $row['id'];
if(count($ids) >= 3) {
// flag items as spam
}
$lastuser = $row['user_id'];
$lasttext = $row['text'];
}
?>
If you use indexes in your MySQL database, you should be able to process N tweets in approximately N*log(N).
You can use the REPLACE function in MySQL to UPDATE or INSERT a new row based on the key:
REPLACE duplicates
SELECT user_id, text
FROM (SELECT user_id, text, count(1) as count
FROM tweets
GROUP BY user_id, text
HAVING count(1) > 2))
I agree with what #MichaelRushton and #Kosta answered but I am wondering if you shouldn't need another table at all? If you build the query, you can ask the first table for the knowledge you are seeking. I especially like the trigger.
Do you just want to pull out a list of possible spam tweets? Try this:
SELECT
user_id,
text,
COUNT(DISTINCT tweet_id)
FROM
tweets
GROUP BY
user_id,
text
HAVING
COUNT(DISTINCT tweet_id) >= 3
You can then use PHP to iterate over the result and INSERT/UPDATE a duplicate_tweets table (although as Chris K mentioned, do you really need a duplicate_tweets table when you can just use this query?).
Before you insert new tweet, check tweets table whether such tweet already exists. If so, insert tweet and insert it in duplicates and duplicates_tweets tables. Or use triggers on insert for tweets table.

Categories