php pdo loop until number not found [duplicate] - php

I am using MySQL and have a table called sales. Its primary key is sales_id.
-------------------------------------
sales_id | invoice_id |
-------------------------------------
1 | 147
2 | 148
3 | 150
For sales_id 3 the invoice_id is supposed to be 149. I want to know which numbers are missing from invoice_id. I start invoice_id at 147 and end invoice_id at 4497. The invoice_id had no relation with sales_id.
Is it possible to know which numbers are missing from invoice_id, using a query?

I presume that you have a table of invoice - INVOICES. You may try:
SELECT invoice_id FROM INVOICES invoice
WHERE NOT EXISTS (SELECT * FROM SALES s WHERE invoice.invoice_id = s.invoice_id)
EDIT: If you don't have the INVOICES table, you may need to take all the invoices out before checking if there's any gap.
SELECT DISTINCT invoice_id FROM SALES ORDER BY invoice_id ASC
SELECT MAX(invoice_id) FROM SALES
then, by php:
for ($i = 1; $i < $max_invoice_id; $i++)
{
if (!in_array($i, $all_invoice_id))
{
$gapId[] = $i;
}
}

If you're just trying to find numbers out of the sequence in the example you've provided you could use something like this:
SELECT *
FROM `sales`
WHERE (
`invoice_id` - 147 - `sales_id`
) = 0
If you can provide a bigger sample set we might be able to tool a better answer for you.

set #suggest_invoice:=147;
select
sales_id,
invoice_id,
#suggest_invoice:=#suggest_invoice+1,
if(invoice_id=#suggest_invoice, 0, 1) as missing_invoice
from sales
order by sales_id;
I guess you almost getting all the records except the first two with missing_invoice=1

As you are searching for invoice_id then make sure you have an index on that column. otherwise queries will be slow.
You can try the following code
$inv_ids=range(147,4497);
$str_inv_ids=implode(",",$inv_ids);
$query="SELECT DISTINCT invoice_id FROM sales WHERE invoice_id IN ($str_inv_ids)";
$result=mysql_query($query);
while ($row = mysql_fetch_assoc($result)) {
$inv_ids_db[]=$row['invoice_id'];
}
// It gives invoice Ids that are in $inv_ids but not in $inv_ids_db
$missing= array_diff($inv_ids,$inv_ids_db);
print_r($missing);

You can find gaps in a MySQL sequence using this query:
SELECT invoice_id+1
FROM sales s
WHERE NOT EXISTS (
SELECT NULL
FROM sales t
WHERE s.invoice_id = t.invoice_id+1
)
HAVING `invoice_id+1` < (SELECT MAX(invoice_id) FROM sales)
ORDER BY invoice_id
This will return all invoice_id missing from the sequence, regardless of sales_id.

Related

SELECT results from another table AS column array

I can't figure out how to get results from 2 tables, in 1 query result (can't simple JOIN)
I have these 2 tables in my MySQL database:
Table 1: sales
id
name
info
Table 2: users
sale_id
user_id
Now, every sale have different number of assigned users. Some sale have 2 users, some sale have 10 users.
In single row, I need to have columns from sale table, and all assigned users to it (connected with same Sale_id)
I need result, something like this:
enter image description here
Try this :
SELECT s.*,
(SELECT GROUP_CONCAT(u.user_id SEPARATOR ', ')
FROM users u
WHERE u.sale_id = s.id) AS users
FROM sales s
Some insight on your programming language would have been nice.
And yes, as suggested by wogsland and icoder, one typically use joins and loop through results to build en array. But the use of GROUP_CONCAT, as Yoleth pointed out, is what you need. I don’t know if it was the goal here, but it can reduce memory used in the result because there is no row repetition.
SELECT info FROM Sales AS s,
(
SELECT sale_id, GROUP_CONCAT(user_id) AS assigned_users
FROM Users
GROUP BY sale_id) AS u
WHERE s.id=u.sale_id;
In a single query, with a fancy JOIN:
SELECT s.info AS info, u.sale_id AS sale_id, GROUP_CONCAT(u.user_id) AS assigned_users
FROM Sales AS s LEFT JOIN Users AS u
ON s.id=u.sale_id
WHERE sale_id IS NOT NULL GROUP BY u.sale_id;
You can simply join two tables and get query result set like this:
saleID | saleName | userID | userName
1 | Oct Sale | 5 | Tim
1 | Oct Sale | 6 | Nik
2 | Nov Sale | 7 | Bill
Then you can walk each row and build associative array from that data:
$sales = array();
while( $row = mysqli_fetch_assoc($result)) {
if (!array_key_exists($row['saleID'], $sales)) {
$sales[$row['saleID']] = array(
'saleID' => $row['saleID'],
'saleName' => $row['saleName'],
'users' => array()
);
}
array_push($sales[$row['saleID']]['users'], array(
'userID' => $row['userID'],
'userName' => $row['userName']
));
}
Well, MySQL isn't going to return you a nice nested array like that. But you can create it by looping through the result. Assuming your MySQL connection is named $mysqli then try something like
$sales = array();
$result = $mysqli->query("SELECT sales.*, users.user_id FROM sales, users WHERE sales.id = users.sales_id");
while ($row = $result->fetch_assoc()) {
$sales[$row->id]['sales_id'] = $row->id;
$sales[$row->id]['name'] = $row->name;
$sales[$row->id]['info'] = $row->info;
$sales[$row->id]['assigned_users'][] = $row->user_id;
}

PHP - Combining Multiple Items Into One

I am attempting to create an end-user page where I present different servers that are available to check-out. A server at any given time can have either an "Available" status or a "Reserved" status. I'm using a MySQL backend. This is how I am doing my query:
SELECT *, COUNT(CASE WHEN Status = 'Available' THEN 1 ELSE NULL END) AS Amount
FROM products GROUP BY id
This is the result I get:
id,Server_Type,Status,Amount
1,BL460,Available,1
2,BL460,Available,1
3,BL460,Reserved,0
4,BL460,Reserved,0
5,BL460,Reserved,0
6,DL360,Available,1
7,DL360,Reserved,0
8,DL360,Reserved,0
Where Reserved is equal to 0, and Available is equal to 1. I only want the end-user to be able to checkout a server in Available status.
To the question: What I want to do in the page is present the list of servers on the page in this way, where Available is equal to the amount:
BL460 - Amount: 2
DL360 - Amount: 1
How can I achieve this format in PHP?
Another option is a crosstab query -
SELECT `Status`,
SUM(IF(`Server_Type` = 'BL460' AND `Status` = 'Available', `Amount`, 0)) AS `BL460`,
SUM(IF(`Server_Type` = 'DL360' AND `Status` = 'Available', `Amount`, 0)) AS `DL360`
FROM `products`
GROUP BY `Status`
Your table would look like this -
Status | BL460 | DL360 |
Available | 2 | 1 |
Reserved | 0 | 0 |
Here is an EXAMPLE
Even better would be to flip things around -
SELECT `server_type`,
SUM(IF(`status` = 'Available', 1, 0)) AS `Available`,
SUM(IF(`status` = 'Reserved', 1, 0)) AS `Reserved`
FROM `servers`
GROUP BY `server_type`;
Which would result in a table that looks like this (based on data in the fiddle) -
server_type | Available | Reserved
BL460 | 3 | 1
DL360 | 1 | 2
Here is that EXAMPLE
Here I could continue to add servers to the table without having to worry about adding them to the query as you would have to do in the first query. If you add an additional status you would have to change the query.
Note in both cases there is no need for an Amount column as the status is the item counted. By placing the load on the database server it makes it much easier to output the HTML as you are just going row bu row as you normally would.
Well, that would probably be easier if you do it directly in your SQL query:
SELECT Server_Type, COUNT(*) AS Count FROM products WHERE Status = 'Available' GROUP BY Server_Type
This should give you exactly the table you want.
If you want to do it in PHP, the easiest solution would probably be to loop through your SQL result and count the number of available servers per Server_Type in an associative array where the Server_Type is your array key:
$amounts = array();
foreach($sql_result as $entry) {
if($entry['Amount'] == 1) {
if(isset($amounts[$entry['Server_Type']])) {
$amounts[$entry['Server_Type']]++;
} else {
$amounts[$entry['Server_Type']] = 1;
}
}
}
echo $amounts;
Edit: in order to print the values as described in the question, you could use the following code snippet:
foreach($amounts as $name=>$amount) {
echo $name + " - Amount: " + $amount + "<br>";
}

How to separate data extracted from the table in PHP

I extracted data from a database and sorted it based on the id. Now i need to separate out the rows with different ids. The aim is to find out the total price for each id and the latest date.
b_id price date
---- ----------------
1 98.30 2014-05-14
1 65.70 2014-05-07
2 14.40 2014-05-06
2 55.60 2014-05-07
2 38.20 2014-04-06
3 84.40 2014-04-02
3 31.30 2014-04-12
3 74.40 2014-05-06
I tried to separate it using -
while ($row = mysqli_fetch_array($result1)) {
if($row['b_id'] == 1){
}
}
But i cannot hard code it. How can i separate out the rows? Am i doing it wrong?
You can do what you want rigth on your query. It would be like:
select b_id, max(date) as maxdate, sum(price) total
from your table
group by b_id
order by b_id
If you want the total price, your extraction could be
SELECT b_id, SUM( price) AS total_price FROM your_table GROUP BY b_id
while ($row = mysqli_fetch_array($result1)) {
echo "Id : " . $row['b_id'] . " Price : " . $row['total_price'];
}
You should use SQL to achieve your goal. It's usually faster when the database handles simple calculations:
SELECT b_id,
SUM(price) AS 'Price',
MAX(date) AS 'Date'
FROM YourTable
GROUP BY b_id

Collect values from DB, group matching values, count it and use in other code

This is what my customers_basket table looks like:
customers_id | products_id | basket_quantity
3 | 56:3121fefbe6043d6fc12e3b3de2c8fc38 | 3
3 | 56:fb4c9278fcfe6225b58c06711a7e62ef | 1
3 | 56:8e334fce09556108f5416e27154b6c27 | 1
3 | 52:f3b9f38e4ddd18035bc04cd264b0f052 | 1
This is the query I'm using:
$products_in_cart_query = "SELECT products_id FROM customers_basket WHERE customers_id = " . $_SESSION['customer_id'] ."";
$products_in_cart = $db->Execute($products_in_cart_query);
$products_in_cart_model = $products_in_cart->fields['products_id'];
$products_in_cart_model = substr($products_in_cart_model, 0, strpos($products_in_cart_model, ":"));
The end result I get is 56,56,56,52
First of all, how do I use the first line's quantity field? I'd need to list that products_id 3 times since quantity is 3. Therefore, the end result needs to be: 56,56,56,56,56,52
or, for easier understanding (56,56,56),56,56,52
And second, how do I count how many same values I have? In this case, I have 5x56 and 1x52. I need to use those counts in my further calculation.
EDIT: further calculations explained
I need to know how many of each product_id I have and then run something like this:
foreach(product_id) {
$shipping_cost += FIXED_VALUE * basket_qty;
}
To get the basket quantity, you have to select it. It would be best if the first portion of the product ID was stored in a separate column, rather than having to do messy operations like substringing.
Query 1: 2-character codes and corresponding quantities
SELECT SUBSTR(products_id, 1, 2) AS product_code, basket_quantity
FROM Customers_Basket
WHERE customers_id = 3;
Query 2: 2-character codes and summed quantities
SELECT product_code, SUM(basket_quantity) AS total_quantity
FROM (SELECT SUBSTR(products_id, 1, 2) AS product_code, basket_quantity
FROM Customers_Basket
WHERE customers_id = 3
)
GROUP BY product_code;
If you really, really, really desperately want 3 rows of data for the product ID 56:3121fefbe6043d6fc12e3b3de2c8fc38, then you have to know ways to generate rows. They're truly painful in the absence of convenient SQL support (so much so, that you'd do better to select a row in PHP with the quantity and then generate the appropriate number of rows in your array in the client-side (PHP) code). I'm going to assume that some variation on these queries will get you the information you want.

PHP/MySQL: Check if something 'belongs-to' something else?

I have two tables: Stores and Items. The relationship is: Stores 1---* Items
In PHP/MySQL what would be the best (fastest/simplest) way to check if a particular item belongs to a particular store.
In other words given for example:
$store_id = 1;
$item_id = 12;
I want to check if item 12 belongs to store 1 (and not some other store).
I usually do a select on Items matching both the store_id and item_id and limit the results to 1. Then check how many rows (0 or 1) were returned with mysql_num_rows. Is there a better way?
Update:
Both tables have an "id" column. The Items table has a "store_id" column.
SELECT COUNT(*) AS count
FROM stores JOIN items USING(store_id)
WHERE item_id = 12
AND store_id = 1
Then you'd get the results, and check of count > 0 or not. However, if I'm getting your DB design right, then you have a very messed up database.
From what you describe, an item can only exist in one store. So my guess of the general layout here would be like this:
STORE ITEM
----- ----
store_id ---| item_id
store_name |--- store_id
... item_name
...
Is this correct? An item can never exist except in the one store? So if it's a screwdriver, every store would need a different item_id to hold it?
A better design would be:
STORE STORE_ITEM ITEM
----- ---------- ----
store_id ------- store_id |------ item_id
store_name item_id ---| item_name
... ...
With a query of
SELECT COUNT(*)
FROM store JOIN store_item USING(store_id)
JOIN item USING(item_id)
WHERE store_id = 1
AND item_id = 12
Both tables have an id, Items has a store_id
SELECT COUNT(*) FROM Items WHERE store_id = $store_id AND id = $item_id
$r = mysql_query("select NULL from Item where storeID = '$store_id' and ItemID = '$item_id'");
if (mysql_fetch_row($r))
{
it belongs...
}
For fun, I'll throw in a one-liner check:
// if item belongs to store
if (current(mysql_fetch_array(mysql_query("SELECT COUNT(*) FROM Items WHERE store_id = $store_id AND id = $item_id"), MYSQL_NUM)))) {
// it belongs!
}

Categories