I have to put down the lines that have two distinct fields with value = 0
Let me explain, all records that have stock_it=0 and stock_eu=0 must go to the bottom of the results
I have used this solution, however, it is not strictly correct because it puts down even rows that do not have both values = 0
$dati = mysql_query("
SELECT *
FROM $tb_article
ORDER BY
FIELD($tb_art.article_status,'n') DESC,
FIELD($tb_art.article_stock_it,'0') ASC,
FIELD($tb_art.article_stock_eu,'0') ASC,
$tb_art.article_rank
");
article_status=n indicates new products and they have to stay on top!
Push to bottom all the article that have stock IT and stock EU = 0 (products not available)
In the end, order the rest of the articles according to the rank assigned
You can use the CASE statement in ORDER BY, like this:
SELECT *
FROM $tb_article
ORDER BY
CASE WHEN article_status = 'n' THEN 0
WHEN article_stock_it = 0 THEN 100000
WHEN article_stock_eu = 0 THEN 100000
ELSE article_rank
END
If you want to use ORDER BY FIELD :
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE tb_article
(
article_stock_it int,
article_stock_eu int,
article_status varchar(11),
article_rank int
);
INSERT INTO tb_article VALUES
(1, 1, 'n', 1)
, (0, 1, 'n', 1)
, (0, 0, 'n', 1)
, (1, 1, 'o', 1)
, (1, 1, 'o', 2);
Query 1:
SELECT *
FROM tb_article
ORDER BY
FIELD(tb_article.article_status,'n') DESC,
FIELD(
IF(tb_article.article_stock_it = 0 AND tb_article.article_stock_eu = 0,'1','0')
,'0') DESC,
tb_article.article_rank
Results:
| article_stock_it | article_stock_eu | article_status | article_rank |
|------------------|------------------|----------------|--------------|
| 1 | 1 | n | 1 |
| 0 | 1 | n | 1 |
| 0 | 0 | n | 1 |
| 1 | 1 | o | 1 |
| 1 | 1 | o | 2 |
Related
I have a recurring_bill table which describes a subscription transaction. I have some duplicates that have the same customerId and chargeId. I want to identify these duplicate records. I also want to make sure IsDeleted is false for both records and the LastDay is in the future or NULL (so its an ongoing charge). My current query shows records that do not have a duplicate. Please help me correct my query.
SELECT * FROM recurring_bills b1
WHERE EXISTS
(SELECT * FROM recurring_bill b2 WHERE b1.customerId = b2.customerId
AND b1.chargeId = b2.chargeId
AND (b2.LastDay > '2022-03-10' OR b2.LastDay IS NULL)
AND b2.IsDeleted = 0)
AND (b1.LastDay > '2022-03-10' OR b1.LastDay IS NULL) AND b1.IsDeleted = 0;
Lets say this is the input
customerId | chargeId | LastDay | IsDeleted
1 | charge1 | NULL | 0
1 | charge1 | 05-23-2022 | 0
2 | charge2 | 05-23-2022 | 0
2 | charge2 | 05-23-2021 | 0
3 | charge3 | NULL | 1
3 | charge3 | NULL | 0
The correct output would be
customerId | chargeId | LastDay | IsDeleted
1 | charge1 | NULL | 0
MySQL version is 5.5.59
Try using EXISTS to identify records with the same customerId, chargeId, etc.. but having a different unique record Id. (I didn't know the name of your column, so used "TheUniqueId" for the example).
Note, when mixing AND/OR operators you must use parentheses to ensure expressions are evaluated in the expected order. Otherwise, the query may return the wrong results.
That said, wouldn't you want to see all of the "duplicates", so you could take action on them, if needed? If so, try:
CREATE TABLE recurring_bills
(`theUniqueId` int auto_increment primary key
, `customerId` int
, `chargeId` varchar(7)
, `LastDay` date
, `IsDeleted` int
)
;
INSERT INTO recurring_bills
(`customerId`, `chargeId`, `LastDay`, `IsDeleted`)
VALUES
(1, 'charge1', NULL, 0),
(1, 'charge1', '2022-05-23', 0),
(2, 'charge2', '2022-05-23', 0),
(2, 'charge2', '2021-05-23', 0),
(3, 'charge3', NULL, 1),
(3, 'charge3', NULL, 0)
;
-- Show all duplicates
SELECT *
FROM recurring_bills dupe
WHERE dupe.IsDeleted = 0
AND ( dupe.LastDay > '2022-03-10' OR
dupe.LastDay IS NULL
)
AND EXISTS (
SELECT NULL
FROM recurring_bills b
WHERE b.customerId = dupe.customerId
AND b.chargeId = dupe.chargeId
AND b.IsDeleted = dupe.IsDeleted
AND b.theUniqueId <> dupe.theUniqueId
AND ( b.LastDay > '2022-03-10' OR
b.LastDay IS NULL
)
)
Results:
theUniqueId | customerId | chargeId | LastDay | IsDeleted
----------: | ---------: | :------- | :--------- | --------:
1 | 1 | charge1 | null | 0
2 | 1 | charge1 | 2022-05-23 | 0
If for some reason you really want a single record per chargeId + customerId, add a GROUP BY
-- Show single record per dupe combination
SELECT *
FROM recurring_bills dupe
WHERE dupe.IsDeleted = 0
AND ( dupe.LastDay > '2022-03-10' OR
dupe.LastDay IS NULL
)
AND EXISTS (
SELECT NULL
FROM recurring_bills b
WHERE b.customerId = dupe.customerId
AND b.chargeId = dupe.chargeId
AND b.IsDeleted = dupe.IsDeleted
AND b.theUniqueId <> dupe.theUniqueId
AND ( b.LastDay > '2022-03-10' OR
b.LastDay IS NULL
)
)
GROUP BY dupe.customerId, dupe.chargeId
Results:
theUniqueId | customerId | chargeId | LastDay | IsDeleted
----------: | ---------: | :------- | :------ | --------:
1 | 1 | charge1 | null | 0
db<>fiddle here
I have such a table, with dates in format YYYY-MM-DD
id | state_id | created_on | closed_on |
1 | 1 | 2020-02-19 | NULL |
2 | 2 | 2020-01-02 | 2020-01-03 |
3 | 1 | 2020-01-05 | NULL |
4 | 4 | 2020-02-07 | 2020-02-08 |
4 | 3 | 2020-02-20 | NULL |
I need to update the STATE with a random state between 2 and 6 WHERE
state_id is 1 OR state_id is 3
created_on is in the past
I can do so with this (IT WORKS PERFECTLY):
UPDATE table SET state_id = FLOOR(2 + rand() * 6)
WHERE created_on < CURRENT_DATE()
AND (state_id=1 OR state_id=3)
What I need to do additionally in the same update, would be to set closed_on:
NULL if the new random state is 3
CURRENT_DATE() if the new random state IS anything but 3
I thought about using SET #newState = FLOOR(2 + rand() * 6), but this way all the records would have the same state_id
is it possible to update with different values?
something like this
UPDATE table SET state_id = FLOOR(2 + rand() * 6), closed_on = IF(new_state_id = 3, NULL, CURRENT_DATE())
WHERE created_on < CURRENT_DATE()
AND (state_id=1 OR state_id=3)
You could self-join the table with a subquery that computes the random number, so you can reuse that value in the outer query:
update mytable t
inner join (
select id, floor(2 + rand() * 6) rnd
from mytable
where state_id in (1, 3)
and created_on < CURRENT_DATE()
) t1 using(id)
set
t.state_id = t1.rnd,
t.closed_on = if(t1.rnd = 3, null, current_date)
So, lets say I have a table called "imports" that looks like this:
| id | importer_id | total_m | total_f |
|====|=============|=========|=========|
| 1 | 1 | 100 | 200 |
| 1 | 1 | 0 | 200 |
And I need the query to return it pivoted or transposed (rows to columns) in this way:
| total_m | sum(total_m) |
| total_f | sum(total_f) |
I can't think on a way to do this without using another table (maybe a temporary table?) and using unions, but there should be a better way to this anyway (maybe with CASE or IF?).
Thanks in advance.
select 'total_m', sum(total_m) from imports
union
select 'total_f', sum(total_f) from imports
http://sqlfiddle.com/#!9/fc1c0/2/0
You can "unpivot" by first expanding the number of rows, which is done below by cross joining a 2 row subquery. Then on each of those rows use relevant case expression conditions to align the former columns to the new rows ("conditional aggregates").
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE imports
(`id` int, `importer_id` int, `total_m` int, `total_f` int)
;
INSERT INTO imports
(`id`, `importer_id`, `total_m`, `total_f`)
VALUES
(1, 1, 100, 200),
(1, 1, 0, 200)
;
Query 1:
select
*
from (
select
i.importer_id
, concat('total_',cj.unpiv) total_type
, sum(case when cj.unpiv = 'm' then total_m
when cj.unpiv = 'f' then total_f else 0 end) as total
from imports i
cross join (select 'm' as unpiv union all select 'f') cj
group by
i.importer_id
, cj.unpiv
) d
Results:
| importer_id | total_type | total |
|-------------|------------|-------|
| 1 | total_f | 400 |
| 1 | total_m | 100 |
I have the following table in mysql:
+ + +
id | state | phone | files
+------------------------------------+
1 | on | 123123 | file1
2 | on | 124423 | file2
3 | off | 123455 | file1
4 | off | 128455 | file3
5 | on | 323132 | file3
6 | off | 124454 | file4
| | |
| | |
| | |
+ + +
I want to select the who has file1, and based on that I check the state, if there is a off state I select the phone number if there isn't any off state I select the first one who has the file1 in table.
In next time the sql query executes, does the same process and if there weren't no off state it returns the next one phone number who hast the file1 but not the previous person. how can I do this?
SELECT t.id
, t.state
, t.phone
, t.file
FROM mytable t
WHERE t.file = 'file1'
ORDER BY t.file, t.state, t.id
LIMIT 1
Your statement should looks something like
select phone from mytable
where file = 'file1'
and state = 'on'
and id > :last_id /* you'll need to provide the previously popped id as a variable */
order by id asc
limit 1;
For a working example in PostgresSQL:
\set last_id 0
select phone from ( values
( 1, 'on', 123123, 'file1' ),
( 2, 'on', 124423, 'file2' ),
( 3, 'off', 123455, 'file1' ),
( 4, 'off', 128455, 'file3' ),
( 5, 'on', 323132, 'file3' ),
( 6, 'off', 124454, 'file4' )
) x ( id, state, phone, file)
where file = 'file1'
and state = 'on'
and id > :last_id
order by id asc
limit 1 ;
Two columns town and priority.
I need to sort table, so that towns with priority=1 would be first and not sorted by name ASC, while the rest gets sorted by name ASC.
How would i do that?
Thanks ;)
Update
SELECT *
FROM map_towns
ORDER BY priority DESC, town
Like this, but so that priority were from 1 to 12+ instead of 12 to 1.
Like that:
town priority
b_town1 1
a_town2 2
d_town3 3
c_town4 4
a_town5 NULL
b_town6 NULL
c_town7 NULL
d_town8 NULL
etc...
By default, MySQL sorts nulls first
I created a small test case (rows inserted non-sorted on purpose).
create table map_towns(
town varchar(30) not null
,priority int null
);
insert into map_towns(town, priority) values('d_town3', 3);
insert into map_towns(town, priority) values('a_town2', 2);
insert into map_towns(town, priority) values('c_town4', 4);
insert into map_towns(town, priority) values('b_town1', 1);
insert into map_towns(town, priority) values('b_town6', NULL);
insert into map_towns(town, priority) values('d_town8', NULL);
insert into map_towns(town, priority) values('a_town5', NULL);
insert into map_towns(town, priority) values('c_town7', NULL);
The following query should do what you ask for.
select town
,priority
,isnull(priority)
from map_towns
order by isnull(priority), priority, town;
+---------+----------+------------------+
| town | priority | isnull(priority) |
+---------+----------+------------------+
| b_town1 | 1 | 0 |
| a_town2 | 2 | 0 |
| d_town3 | 3 | 0 |
| c_town4 | 4 | 0 |
| a_town5 | NULL | 1 |
| b_town6 | NULL | 1 |
| c_town7 | NULL | 1 |
| d_town8 | NULL | 1 |
+---------+----------+------------------+
Here is a link on ISNULL documentation
My idea:
SELECT * FROM Towns
ORDER BY IF(priority = 1, 0, 1) ASC,
town ASC;
Well just simply make it so that the Priority by default is 0, and then each Town you have you can sort them based on a number. I would normally do something like DisplayOrder which in terms could be your Priority.
something like this.
SELECT * FROM Towns
ORDER BY priority ASC,
name ASC;
So if you have something like
id, name, priority
-----------------------
1, Smithtown, 0
2, Rocktown, 2
3, Georgetown, 1
4, Rockton, 2
The ordering then would be
1, Smithtown, 0
3, Georgetown, 1
4, Rockton, 2
2, Rocktown, 2
SELECT *
FROM map_towns
ORDER BY
priority IS NULL, priority, town