sort same field from different tables - php

I have somes tables (around 20) with the same structure and I'm trying to sort them with a php script and insert them in a new table with the cheapest price in cheapest1, then cheapest2 for more expensive... and the most expensive in column cheapest20:
table A:
id
name
price
table B:
id
name
price
table X:
id
name
price
tableResult:
id
name
cheapest1
price1
cheapest2
price2
...
cheapestX
priceX
My code so far is:
(SELECT id, price, name FROM tableA WHERE id = $id)
UNION
(SELECT id, price, name FROM tableB WHERE id = $id)
ORDER BY price ASC
I have been looking for different solutions but it takes too long to SELECT for 15000 rows so I guess there is another way to do it.
I haven't looked for the update query yet, I need to fix the select in the first time.
Any suggestion?
EDIT: clarified question, with more tables
EDIT2: solution
I finally got it right. This is the query to select the cheapest:
I select each id and I browse:
(SELECT price AS P1, name, id FROM tableA WHERE id = ?) UNION (SELECT price AS P1, name, id FROM tableB WHERE id = ?) UNION (SELECT price AS P1, name, id FROM tableC WHERE id = ?) ORDER BY P1 ASC
Then I Insert in the new table as glglgl suggested:
('INSERT INTO table (id, name, Position, price) VALUES (?, ?, ?, ?) ');

If you have control over the final structure of the tables: Don't do that. Instead, use only one table and add a field for indicating which purpose it serves.
The target table is not structured well either. Instead, you should use
tableResult:
id
name
cheapestorder
cheapest
price
which makes all easier.
Thus, instead of having one row containing
id=10, name=foo, cheapest1=a, cheapestprice1=10, cheapest2=b, cheapestprice2=13,
you have several rows
id=10, name=foo, cheapestorder=1, cheapest=a, cheapestprice=10
id=10, name=foo, cheapestorder=2, cheapest=b, cheapestprice=13
(This process is called "normalization" in database theory.)
Putting all input tables into one simplifies dcp's query:
SELECT name,
max(mxprice) mxprice,
min(mnprice) mnprice
FROM
(
SELECT name,
max(price) mxprice,
min(price) mnprice
FROM tableABC
GROUP BY NAME, tbltag
) a
GROUP BY NAME
or maybe even just
SELECT name,
max(price) mxprice,
min(price) mnprice
FROM tableABC
GROUP BY NAME
.

I did this on Oracle, but syntax should be very similar for MySQL (the select should work without any changes at all).
CREATE TABLE tableA (NAME VARCHAR2(100), price FLOAT);
CREATE TABLE tableB (NAME VARCHAR2(100), price FLOAT);
INSERT INTO tableA VALUES ('a',14.23);
INSERT INTO tableA VALUES ('b',15.23);
INSERT INTO tableA VALUES ('b',16.23);
INSERT INTO tableB VALUES ('a',12.23);
INSERT INTO tableB VALUES ('a',13.23);
INSERT INTO tableB VALUES ('b',9.23);
SELECT name
, max(mxprice) mxprice
, min(mnprice) mnprice
FROM
(
SELECT name
, max(price) mxprice
, min(price) mnprice
FROM tableA
GROUP BY NAME
UNION ALL
SELECT name
, max(price) mxprice
, min(price) mnprice
FROM tableB
GROUP BY NAME
) a
GROUP BY NAME
Result:
NAME MXPRICE MNPRICE
1 a 14.23 12.23
2 b 16.23 9.23

Related

How to choose oldest row from the table of similar rows?

I have a table. Table has structure of id, name, color, product_id.
And the table has multiple rows with the same product_id.
With SQL query from PHP file - I would like to choose only one, the oldest, row. (The first one that was added to the current table).
What query should I use or approach?
Thank you!
Just making up a bit of mockup data ... Note the notes I put in. And I trust it's a newer version of MySQL, as the older ones did not support ROW_NUMBER() OVER() .
Here goes:
WITH
-- input ... you *need* a timestamp to identify the oldest ---
indata(id, name, color, product_id,ts) AS (
SELECT 1,'Arthur','blue' ,42,TIMESTAMP'2021-01-31 17:45:00'
UNION ALL SELECT 1,'Arthur','blue' ,42,TIMESTAMP'2021-01-31 17:50:00'
UNION ALL SELECT 1,'Arthur','blue' ,42,TIMESTAMP'2021-01-31 17:55:00'
UNION ALL SELECT 1,'Arthur','blue' ,42,TIMESTAMP'2021-01-31 18:00:00'
UNION ALL SELECT 2,'Ford' ,'red' ,42,TIMESTAMP'2021-01-31 17:45:00'
UNION ALL SELECT 2,'Ford' ,'blue', 42,TIMESTAMP'2021-01-31 17:50:00'
UNION ALL SELECT 2,'Ford' ,'green',42,TIMESTAMP'2021-01-31 17:55:00'
UNION ALL SELECT 2,'Ford' ,'cyan' ,42,TIMESTAMP'2021-01-31 18:00:00'
)
,
-- select all, plus a rank, on which you will filter outside ..
with_rank AS (
SELECT
*
, ROW_NUMBER() OVER(PARTITION BY id ORDER BY ts) AS rnk
FROM indata
)
SELECT
id
, name
, color
, product_id
, ts
FROM with_rank
WHERE rnk = 1
id|name |color|product_id|ts
1|Arthur|blue |42 |2021-01-31 17:45:00
2|Ford |red |42 |2021-01-31 17:45:00
One method is a correlated subquery:
select t.*
from t
where t.id = (select min(t2.id)
from t t2
where t2.product_id = t.product_id
);
This assumes that id is incrementing with each insertion. If not, you have no way of knowing what the "oldest" row is. SQL tables represent unordered sets, so there is no "oldest" row unless a column contains that information.
SELECT * FROM TableName WHERE product_id = ProductID ORDER BY product_id LIMIT 1;

How to count every month records from Table1 and Store it in Table2

Let's Say I have 2 tables
In Table1 I have 3 columns named as
Table1
Id | Name | Date (Format: 12-01-2019)
1 ABC 22-08-2019
2 XYZ 23-07-2019
Now My Question is How to store the Month wise count in another Table(i.e, Table2)
Expected Result:
Table 2
Month | Count
08/Aug 1
07/July 1
I searched many queries but I didn't find a better one
Can anyone provide me this sql query?
OR
If can you provide SQL query which stores all these count in separate column in Table1 with an extra column
merge into table_2 tgt
using
(select trunc(dt, 'month') dt, count(*) cnt
from table_1
group by trunc(dt, 'month')
) src on (tgt.dt = src.dt)
when not matched then insert (tgt.dt, tgt.cnt)
values (src.dt, src.cnt);
INSERT INTO table2(month,count)
SELECT
MONTH(Date) AS m, COUNT(DISTINCT Id)
FROM
table1 GROUP BY m;
This can be done in one query
Insert into Table2 (Column1, Column2)
Select Count(*), DATEColumn from Table1 group by DATEColumn
I am not sure which database your are using this work on MSSQL.

Sum more than 1 table from SQL on codeigniter

need a small help to figure out this situation.
I see that codeigniter is not supporting UNION and i want to figure out this method to get the total sum for 2 tables, with same id of product.
The issue is that on sum 2 tables, the values are duplicating or multiplicative.
Link to SQL Fiddle
Structure :
create table products
(id int, name varchar(9));
insert into products
(id, name)
values
(1,'Product 1'),
(2,'Product 2'),
(3,'Product 3');
create table p_items
(puid int, prid int, quantity int);
insert into p_items
(puid, prid, quantity)
values
(11,1,100),
(11,2,100),
(11,2,100),
(14,2,100),
(14,3,100),
(15,3,100);
create table s_items
(puid int, prid int, quantity int);
insert into s_items
(puid, prid, quantity)
values
(11,1,1),
(11,2,1),
(11,2,1),
(13,2,1),
(15,3,1),
(13,3,1);
Execute in normal SQL:
select a.puid, b.name, a.prid, sum(a.quantity) as P_ITEMS, sum(c.quantity) as S_ITEMS
from p_items a
join products b
on b.id = a.prid
join s_items c
on c.prid = a.prid
group by a.prid;
Codeigniter Function:
$this->alerts
->select('products.id as productid, products.name, sumt(p_items.quantity), sum(s_items.quantity)', FALSE)
->from('products')
->join('p_items', 'products.id = p_items.prid', 'left')
->join('s_items', 'products.id = s_items.prid')
->group_by("products.id");
echo $this->alerts->generate();
Any help is very appreciated.
Your problem is your producing a cartesian product and thus getting your duplicated sums. Look at Product ID 3 for example. You're associating that with p_items prid = 3. By itself, that would return you 200. However, once you then join on s_items prid = 3, now for each row in s_items, it has to match with each row in p_items. Meaning:
14 3 100 15 3 1
14 3 100 15 3 1
15 3 100 15 3 1
15 3 100 15 3 1
---------------
400 4
Besides the product table, which table is your master table? If you use p_items, you want get row 13 from s_items. Likewise, if you use s_items, you won't get rows 14 from p_items.
You can accomplish this using a subquery:
select b.id,
b.name,
P_ITEMS,
S_ITEMS
from products b
left join
(SELECT prid, SUM(quantity) as P_Items
FROM p_items
GROUP BY prid)
a on b.id = a.prid
left join
(SELECT prid, SUM(quantity) as S_Items
FROM s_items
GROUP BY prid)
c on c.prid = a.prid
group by b.id, b.name
And the updated Fiddel: http://sqlfiddle.com/#!2/62b45/12
Good luck.
If the best way to get the answer you want is with a union query, and codeigniter does not let you write one, don't use codeigniter to write your query. Put it in a stored procedure and call the stored procedure with codeigniter.

How to select a column value as a column name and group the results as a row

How do I select a column value as a column name and group the results as a row.
I have a table as such:
id articleId label value
1 1 title Example title
2 1 description This is the description
3 1 author Me
4 2 title Example of another type of article
5 2 description Short description
6 2 author Someone else
Is it possible to select all of the rows and use the label as the column name and the value as the value of that column name and then group them by the article name.
So how I would like to have it returned:
articleId title description author
1 Example title This is the.. Me
2 Example of an.. Short descr.. Someone else
I'm using this for a CMS where the user can define the fields for an article so we don't have to customize the table's. This is why i'm not making the tables as the I would like to have it returned. I am also aware that I can just as easily convert the result to this in php.
-- edit --
Can this be done without knowing what labels are added? In this example im using title, description and author. But it could very well be something totally different like title, shortDescription, availableTo, techInformation, etc.. The idea is that the article's are customizable for the user without needing to change the database and query's
I figured I'd better post as an answer, even if not what OP would like to hear. What you are asking to do is to populate a query with a variable number of columns based on the distinct values within column label, all associated with articleID. Taking your specific example, the following would be the resultant query that I would most likely go to in this instance (though the example from #Devart is equally valid)
SELECT
t.id,
t.articleId,
t1.value AS title,
t2.value AS description,
t3.value AS author
FROM `tableName` t
LEFT JOIN `tablename` t1
ON t1.article_id = t.article_id AND t1.label = 'title'
LEFT JOIN `tablename` t2
ON t2.article_id = t.article_id AND t2.label = 'description'
LEFT JOIN `tablename` t3
ON t3.article_id = t.article_id AND t3.label = 'author'
Now expanding this to account for up to n labels, we get the following query (metacode included, this query will NOT execute verbatim)
SELECT DISTINCT label FROM `tableName`;
SELECT
t.id,
t.articleId
// for (i=1;i<= number of distinct labels) {
,t[i].value AS [value[i]]
// }
FROM `tableName` t
// for (i=1;i<= number of distinct labels) {
LEFT JOIN `tablename` t[i]
ON t[i].article_id = t.article_id AND t[i].label = [value[i]]
// }
;
So what you can do is one of the following.
SELECT t.* FROM tablename t and then have PHP process it as required
SELECT DISTINCT label FROM tablename and have PHP build the second query with the many LEFT JOINs (or MAX / GROUP BY logic if preferred)
Create a Stored Procedure to do the same as #2. This would most likely be more efficient than #2 however may be less efficient overall than #1.
You can use pivote table trick -
SELECT
articleId,
MAX(IF(label = 'title', value, NULL)) AS title,
MAX(IF(label = 'description', value, NULL)) AS description,
MAX(IF(label = 'author', value, NULL)) AS author
FROM
table
GROUP BY
articleId
Try below :
select t1.articleId,t1.title,t1.description,t1.author
from tablename as t1
left join (select max(articleId) as articleId
from tablename
group by articleId ) as t2
on t1.articleId=tsm.articleId where [.....]

Getting random record from database with group by

Hello i have a question on picking random entries from a database. I have 4 tables, products, bids and autobids, and users.
Products
-------
id 20,21,22,23,24(prime_key)
price...........
etc...........
users
-------
id(prim_key)
name user1,user2,user3
etc
bids
-------
product_id
user_id
created
autobids
--------
user_id
product_id
Now a multiple users can have an autobid on an product. So for the next bidder I want to select a random user from the autobid table
example of the query in language:
for each product in the autobid table I want a random user, which is not the last bidder.
On product 20 has user1,user2,user3 an autobidding.
On product 21 has user1,user2,user3 an autobidding
Then I want a resultset that looks for example like this
20 – user2
21 – user3
Just a random user. I tried miximg the GOUP BY (product_id) and making it RAND(), but I just can't get the right values from it. Now I am getting a random user, but all the values that go with it don't match.
Can someone please help me construct this query, I am using php and mysql
The first part of the solution is concerned with identifying the latest bid for each product: these eventually wind up in temporary table "latest_bid".
Then, we assign randon rank values to each autobid for each product - excluding the latest bid for each product. We then choose the highest rank value for each product, and then output the user_id and product_id of the autobids with those highest rank values.
create temporary table lastbids (product_id int not null,
created datetime not null,
primary key( product_id, created ) );
insert into lastbids
select product_id, max(created)
from bids
group by product_id;
create temporary table latest_bid ( user_id int not null,
product_id int not null,
primary key( user_id, product_id) );
insert into latest_bid
select product_id, user_id
from bids b
join lastbids lb on lb.product_id = b.product_id and lb.created = b.created;
create temporary table rank ( user_id int not null,
product_id int not null,
rank float not null,
primary key( product_id, rank ));
# "ignore" duplicates - it should not matter
# left join on latest_bid to exclude latest_bid for each product
insert ignore into rank
select user_id, product_id, rand()
from autobids a
left join latest_bid lb on a.user_id = lb.user_id and a.product_id = lb.product_id
where lb.user_id is null;
create temporary table choice
as select product_id,max(rank) choice
from rank group by product_id;
select user_id, res.product_id from rank res
join choice on res.product_id = choice.product_id and res.rank = choice.choice;
You can use the LIMIT statement in conjunction with server-side PREPARE.
Here is an example that selects a random row from the table mysql.help_category:
select #choice:= (rand() * count(*)) from mysql.help_category;
prepare rand_msg from 'select * from mysql.help_category limit ?,1';
execute rand_msg using #choice;
deallocate prepare rand_msg;
This will need refining to prevent #choice becoming zero, but the general idea works.
Alternatively, your application can construct the count itself by running the first select, and constructing the second select with a hard-coded limit value:
select count(*) from mysql.help_category;
# application then calculates limit value and constructs the select statement:
select * from mysql.help_category limit 5,1;

Categories