I have a following result set:
request_id | p_id
66 | 10
66 | 10
66 | 10
66 | 22
66 | 22
76 | 23
76 | 24
I am trying to select rows that excludes records with certain combination values:
request_id | product_id
66 | 10
76 | 23
So the output result set should contain only these records:
66 | 22
66 | 22
76 | 24
I tried doing:
select * from `table`
where request_id NOT IN (66, 76) AND product_id NOT IN (10, 22)
But this gives me empty resultset.
How do I exclude just the combination of those two values?
You can try below -
DEMO
select * from `table`
where (request_id, p_id) NOT IN ((66, 10),(76,23))
OUTPUT:
request_id p_id
66 22
66 22
76 24
Try use something like this:
SELECT DISTINCT *
FROM TABLE1
WHERE TABLE1.request_id NOT IN
(
SELECT r_id
FROM TABLE2
)
AND TABLE1.p_id NOT IN
(
SELECT p_id
FROM TABLE2
)
That is a better way:
SELECT DISTINCT *
FROM TABLE1
LEFT JOIN TABLE2 ON TABLE1.request_id = TABLE2.r_id
AND TABLE1.p_id = TABLE2.p_id
WHERE TABLE2.p_id IS NULL
Related
I need help with a MySQL query to count the number of times a combination of the same age_from and age_to occur.
Sample data:
age_from age_to
+---------+-------+
18 | 100
30 | 75
18 | 50
18 | 100
30 | 75
18 | 50
30 | 75
+---------+------+
Desired result:
18 to 100 = 2
30 to 75 = 3
18 to 50 = 2
I have already tried this:
SELECT
`p_age_from` AS `age_from`,
`p_age_to` AS `age_to`,
COUNT(`p_age_from`) AS `user_count`
FROM `user`
GROUP BY `p_age_from`, `p_age_to`
ORDER BY `p_age_from`
You can use CONCAT to join the age_from and age_to values. Then use this to group and count the data:
SELECT
CONCAT(`age_from`,' to ',`age_to`) as 'grouping',
COUNT('grouping') AS `user_count`
FROM `user`
GROUP BY grouping
You can get your result using following query
SELECT CONCAT(age_from,' to ',age_to,' = ',count(age_to)) as 'age_from to age_to'
FROM user
GROUP BY age_from, age_to
ORDER BY age_from;
hi I need to insert values into a new table (consist of 3 colunms) where I have a column named verad_id which has 250 values and now while inserting data i need to load all the values expect for 6 verad_id which has zero values for reage field.
example main table:-
verad_id reage value
998 0 38
8484 4 43
998 3 33
432 0 23
233 43 26
556 0 53
432 9 33
now i need to insert values expect for verad_id 998 and 432 which has reage value as 0
after inserting table should be like this
verad_id reage value
8484 4 43
998 3 33
233 43 26
556 0 53
432 9 33
I have tried this but not working
tried case 1:-
insert into finaltable
select
verad_id,
reage,
value
from main_table where verad_id = '998' or verad_id = '432' and reage != 0;
tried this but this query is not working
tried case 2:-
insert into finaltable
select
verad_id,
reage,
value
from main_table where verad_id in ( '998' , '432') and reage != 0;
in this case I was able to load data of verad_id '998' and '432' with reage not equal to 0 here i am missing data of other verad_id.
can any one please help me with this
To put it simple what you want to do is get grouped data from table main_table and each group sorted by the column reage in a DESC order.
Once you've got those results you wish to insert them into the table called finaltalbe
In this case you could use a subselect in which you define the order in which the results should be displayed, then select a group around that and MySQL will show the values of the first row in each grouped set.
INSERT INTO finaltable
SELECT * FROM (SELECT * FROM main_table ORDER BY `reage` DESC) AS `sorted` GROUP BY `verad_id`;
this will result in the table finaltable with the following data
| verad_id | reage | value |
|----------|-------|-------|
| 233 | 43 | 26 |
| 432 | 9 | 33 |
| 556 | 0 | 53 |
| 998 | 3 | 33 |
| 8484 | 4 | 43 |
I have two columns coming from my sql query- month, value i.e. values are coming monthwise. My requirement is to club these months in the group of 3 months wise...and the values should come the average of these 3.
Ex.I have following data-
Month Values
Mar-14 50
Apr-14 51
May-14 52
Jun-14 53
Jul-14 54
Aug-14 55
Sep-14 56
Oct-14 57
Nov-14 58
Dec-14 59
Jan-15 60
Feb-15 61
Mar-15 62
Apr-15 63
May-15 64
Jun-15 65
Jul-15 66
Aug-15 67
Sep-15 68
Oct-15 69
Nov-15 70
Dec-15 71
Jan-16 72
Feb-16 73
Mar-16 74
Apr-16 75
May-16 76
Jun-16 77
Jul-16 78
Aug-16 79
Sep-16 80
Oct-16 81
Nov-16 82
Dec-16 83
Jan-17 84
Feb-17 85
Mar-17 86
How can I achieve following output in MySql-
3 Months Clubing Avg of Values
Mar-14 51
Jun-14 54
Sep-14 57
Dec-14 60
Mar-15 63
Jun-15 66
Sep-15 69
Dec-15 72
Mar-16 75
Jun-16 78
Sep-16 81
Thanks in Advance
A bit messy but you could use variables -assuming you have an incrementing id column (or soemthing you can order by)
drop table if exists t;
create table t(id int auto_increment primary key,Month varchar(10), Valus int);
insert into t (month,valus) values
('Mar-14', 50),
('Apr-14', 51),
('May-14', 52),
('Jun-14', 53),
('Jul-14', 54),
('Aug-14', 55),
('Sep-14', 56),
('Oct-14', 57),
('Nov-14', 58),
('Dec-14', 59);
select id,mth,rt
from
(
select id,month,valus,
#count:=#count+1 counter,
if(#count=1,#mth:=month,#mth:=#mth) mth,
if(#count=1,#block:=#block+1,#block:=#block) block,
if(#count<3,#sum:=#sum+valus,#sum:=(#sum+valus) / 3) rt,
if(#count=3,#count:=0,#count:=#count) creset,
if(#count=0,#sum:=0,#sum:=#sum) sumreset
from t
cross join (select #m ='',#count:=0,#sum:=0,#block:=0,#mth:='') s
order by id
)t
where counter = 3;
+----+--------+------+
| id | mth | rt |
+----+--------+------+
| 3 | Mar-14 | 51 |
| 6 | Jun-14 | 54 |
| 9 | Sep-14 | 57 |
+----+--------+------+
3 rows in set (0.03 sec)
Slightly less messy but using sql's avg function and using variables to fill down the first month in a 3 month block
select block,mth,avg(valus)
from
(
select id,month,valus,
#count:=#count+1 counter,
if(#count=1,#mth:=month,#mth:=#mth) mth,
if(#count=1,#block:=#block+1,#block:=#block) block,
if(#count=3,#count:=0,#count:=#count) creset
from t
cross join (select #block:=0,#count:=0,#mth:='') s
order by id
) t
group by block,mth
order by block,mth
+-------+--------+------------+
| block | mth | avg(valus) |
+-------+--------+------------+
| 1 | Mar-14 | 51.0000 |
| 2 | Jun-14 | 54.0000 |
| 3 | Sep-14 | 57.0000 |
| 4 | Dec-14 | 59.0000 |
+-------+--------+------------+
4 rows in set (0.05 sec)
Try this
create temporary table tab (month1 varchar(30), id int);
insert into tab (month1,id)
values('Mar-14' ,50),
('Apr-14' ,51),
('May-14' ,52),
('Jun-14' ,53),
('Jul-14' ,54),
('Aug-14' ,55),
('Sep-14' ,56),
('Oct-14' ,57),
('Nov-14' ,58),
('Dec-14' ,59),
('Jan-15' ,60),
('Feb-15' ,61),
('Mar-14' ,62);
set #row_number = 0;
select *
from tab where (#row_number := #row_number+1)%3= 1;
Result
month1 id
'Mar-14' '50'
'Jun-14' '53'
'Sep-14' '56'
'Dec-14' '59'
'Mar-14' '62'
In a re-print of a deleted question an hour ago,
if I wanted to print out the numbers 1-100, with 10 numbers to a line
in the mysql shell, how would I go about doing that?
Community wiki answer so as not to collect points. Edit at will.
select theAnswer
from
( select #rn:=#rn+1 as rownum,
concat(1+(#rn-1)*10,' ',2+(#rn-1)*10,' ',3+(#rn-1)*10,' ',4+(#rn-1)*10,' ',5+(#rn-1)*10,' ',
6+(#rn-1)*10,' ',7+(#rn-1)*10,' ',8+(#rn-1)*10,' ',9+(#rn-1)*10,' ',10+(#rn-1)*10,' ') as theAnswer
from (select #rn:=0) params1
cross join (select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 10) params2
) xDerived;
+---------------------------------+
| theAnswer |
+---------------------------------+
| 1 2 3 4 5 6 7 8 9 10 |
| 11 12 13 14 15 16 17 18 19 20 |
| 21 22 23 24 25 26 27 28 29 30 |
| 31 32 33 34 35 36 37 38 39 40 |
| 41 42 43 44 45 46 47 48 49 50 |
| 51 52 53 54 55 56 57 58 59 60 |
| 61 62 63 64 65 66 67 68 69 70 |
| 71 72 73 74 75 76 77 78 79 80 |
| 81 82 83 84 85 86 87 88 89 90 |
| 91 92 93 94 95 96 97 98 99 100 |
+---------------------------------+
The stuff inside of the from ( ) is a derived table, and every derived table needs an alias, which is xDerived.
#rn is a row number variable. It gets initialized in the params1 derived table. One row.
params2 is another derived table, with rows 1 to 10 as values.
The cross join creates a cartesian product (all permutations) of a 1x10 which results in 10 rows, with #rn getting incremented with each row.
As we only want one column of output, the outer wrapper does the final select for just one column to avoid outputting the row number column.
If one wanted to use a WHILE DO loop in mysql, one could use a stored procedure.
Generally what i do is create a table (normally a temp table) and populate that with a stored procedure.
CREATE TABLE `numTable` (
`Id` int(11) NOT NULL auto_increment,
PRIMARY KEY (`Id`)
)//
CREATE PROCEDURE dowhile(IN tableLimit INT)
BEGIN
DECLARE pointer INT DEFAULT tableLimit;
WHILE pointer > 0 DO
INSERT numTable VALUES (NULL);
SET pointer = pointer - 1;
END WHILE;
END//
CALL dowhile(100)//
now you may need to use DELIMITER but for the sake of consistency i have just copied what worked in SQL Fiddle by setting the Schema Delimiter to be // (forth button bellow the Schema Window)
then from there i then do a select of this table by giving each row a group id. since you want groups of 10 i have set the group to be multiples of 10 and then group by this group id using GROUP_CONCAT to make the rows.
select myRow
from (
SELECT group_concat(id SEPARATOR ', ') as `myRow`, CEIL(id/10) as `groupId`
FROM numTable group by `groupID`) as myTable;
SQL Fiddle
since we don't want to show the group id i then make this a sub-select and only select my new rows. if you use this in something like PHP or C# to output the rows you can just do the one select since you don't have to output everything you get from a query result.
In MariaDB with the sequence plugin:
select group_concat(seq order by seq separator ' ')
from seq_1_to_100
group by (seq-1) div 10;
| group_concat(seq order by seq separator ' ') |
|----------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 |
| 11 12 13 14 15 16 17 18 19 20 |
| 21 22 23 24 25 26 27 28 29 30 |
| 31 32 33 34 35 36 37 38 39 40 |
| 41 42 43 44 45 46 47 48 49 50 |
| 51 52 53 54 55 56 57 58 59 60 |
| 61 62 63 64 65 66 67 68 69 70 |
| 71 72 73 74 75 76 77 78 79 80 |
| 81 82 83 84 85 86 87 88 89 90 |
| 91 92 93 94 95 96 97 98 99 100 |
A generic solution:
set #num_cols := 10;
set #max := 100;
select group_concat(seq order by seq separator ' ')
from seq_1_to_1000000
where seq <= #max
group by (seq-1) div #num_cols
order by min(seq);
If you want them all in one cell:
select group_concat(col separator '\n')
from (
select group_concat(seq order by seq separator '\t') as col
from seq_1_to_1000000
where seq <= #max
group by (seq-1) div #num_cols
) drv
Want to have columns?
set #num_cols := 7;
set #num_rows := 3;
set #sql := (
concat('select ', (
select group_concat('(seq-1)*', #num_cols, '+', seq, ' as c', seq)
from seq_1_to_1000000
where seq <= #num_cols
),' from seq_1_to_1000000 where seq<=', #num_rows)
);
prepare stmt from #sql;
execute stmt;
| c1 | c2 | c3 | c4 | c5 | c6 | c7 |
|----|----|----|----|----|----|----|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
If you don't have MariaDB with the sequence plugin, you can create a helper table with sequence numbers. Ask Drew how to do that :-)
I'm trying to generate a query to tell me how many products were ordered from the site, but in groups.
This is the structure of my table (product_orders):
product_order_id | order_id | product_id
168 | 64 | 17
168 | 64 | 18
168 | 64 | 16
168 | 64 | 15
168 | 64 | 19
168 | 65 | 17
168 | 65 | 18
168 | 66 | 16
168 | 66 | 15
168 | 66 | 19
168 | 67 | 15
What I need to be able to get, is a count of orders where the user purchased:
ONLY product_id 17 AND 18
ONLY product_id 17 AND 16 AND 15
It's that AND that's driving me a bit crazy with this query, and the fact that that 1 order has multiple products. Any ideas? I'm sure I'm overlooking something simple here.
Thanks.
B.
You can do this with a fairly clunky EXISTS statement
SELECT COUNT(DISTINCT order_id) FROM product_orders p1
WHERE EXISTS (SELECT * FROM product_orders p2
WHERE p1.order_id = p2.order_id
AND p2.product_id = 17)
AND EXISTS (SELECT * FROM product_orders p3
WHERE p1.order_id = p3.order_id
AND p3.product_id = 18)
AND NOT EXISTS (SELECT * FROM product_orders p4
WHERE p1.order_id = p4.order_id
AND p4.product_id <> 17
AND p4.product_id <> 18);
And you can obviously you repeat this pattern for the {15,16,17} set.
Assuming the product_id's are unique per order in product_orders table, we can count matching and non-matching and compare. So there should be exactly two entries with product_id 17 or 18, and none that are not 17 or 18 to match the first scenario. The second scenario would be the same logic, except there should be exactly three entries with product_id 15 or 16 or 17, and none that don't match any:
select count(*) from (
select distinct order_id from product_orders po1
where (
(select count(product_id) from product_orders po2
where po1.order_id = po2.order_id and
po2.product_id in (17, 18)) = 2
and
(select count(product_id) from product_orders po3
where po1.order_id = po3.order_id and
po3.product_id not in (17, 18)) = 0
) or (
(select count(product_id) from product_orders po4
where po1.order_id = po4.order_id and
po4.product_id in (15, 16, 17)) = 3
and
(select count(product_id) from product_orders po5
where po1.order_id = po5.order_id and
po5.product_id not in (15, 16, 17)) = 0
)
) p
There is only one order that satisfies all the conditions: order_id 65.
Working Demo: http://sqlize.com/5Q5Lo7Oa71