Having this table with 3 columns:
id name flag
1 A 1
2 A 0
3 A 0
4 B 0
5 B 0
6 C 0
7 D 1
I want to select all groups that does not have flag = 1
Expected results:
name
B
C
this is not working because ( correctly ) include all groups that has at list one
SELECT name
FROM test
WHERE flag <> '1'
GROUP BY name
Aggregation is one way to do this, but you need a HAVING clause to assert that a matching group has no flag = 1:
SELECT name
FROM test
GROUP BY name
HAVING SUM(flag = 1) = 0;
Demo
You could also use a subquery with exists logic:
SELECT t1.name
FROM test t1
WHERE NOT EXISTS (SELECT 1 FROM test t2 WHERE t2.name = t1.name AND t2.flag = 1);
You can use below query to get the desired output.
SELECT `name`
FROM `test`
WHERE `name` <> ALL ( SELECT `name` FROM `test` WHERE `flag` = 1 )
GROUP BY `name`;
Just use SELECT DISTINCT:
SELECT DISTINCT `name`
FROM `test`
WHERE `name` NOT IN (SELECT DISTINCT `name` FROM `test` WHERE `flag` = 1);
Related
I have this two MySQL statements from same table :
SELECT
`table1`.`product_id` As product_id,
COUNT(DISTINCT(table1.user_id)) AS NonebuyersNumber
FROM table1
WHERE status = 1 AND `ispaid` != 2
GROUP BY `table1`.`product_id`
The second statement is :
SELECT l
`table1`.`product_id` As product_id,
COUNT(DISTINCT(table1.user_id)) AS BuyersNumber
FROM table1
WHERE `ispaid` = 1
GROUP BY `table1`.`product_id`
The result that I want is a table like this one :
I tried to use Union but doesn't work because I have two different columns
Any idea how I can get this 3rd table?
Use conditional aggregation:
SELECT
product_id,
COUNT(DISTINCT CASE WHEN status = 1 AND ispaid != 2
THEN user_id ELSE NULL END) AS NonebuyersNumber
COUNT(DISTINCT CASE WHEN ispaid = 1 THEN user_id ELSE NULL END) AS BuyersNumber
FROM table1
WHERE
(status = 1 AND ispaid != 2) OR
ispaid = 1
GROUP BY
product_id;
This should work because both of your queries aggregate over the product_id and the only differences are the WHERE clauses. We can combine the records from both queries and then use CASE expressions to target records intended for each original query.
SELECT t1.product_id AS product_id
SELECT CASE WHEN t1.NonebuyersNumber IS NULL
THEN 0
ELSE t1.NonebuyersNumber
END
AS NonebuyersNumber,
SELECT CASE WHEN t2.BuyersNumber IS NULL
THEN 0
ELSE t2.BuyersNumber
END
AS BuyersNumber
FROM
(SELECT
`table1`.`product_id` As product_id ,
COUNT(DISTINCT(table1.user_id)) AS NonebuyersNumber
FROM table1 WHERE status =1
AND `ispaid` != 2
GROUP BY `table1`.`product_id`)
AS t1
INNER JOIN
(SELECT
`table1`.`product_id` As product_id ,
COUNT(DISTINCT(table1.user_id)) AS BuyersNumber
FROM table1 WHERE `ispaid` = 1
GROUP BY `table1`.`product_id`)
AS t2
ON t1.product_id = t2.product_id
Basically, you need following
Join both the views on product_id
Use CASE statements in select in case one of the buyers numbers is NULL
I have this kind of table (simplified):
orders sample data below
---------------------------------------------
id INT: 1 2 3 4 5
userid INT 10 10 10 20 20
status CHAR(1) A A B A C
and want to select all orders where for each userid status is IN ('A','B') but have no orders at all IN ('C','D').
So output for above data would give orders with ID=1, 2 and 3. User ID=10 have orders A and B, but no C or D.
In other words: Select orders for customers who have orders with status A or B, but none of statuses C or D.
I started with this:
SELECT
xcart_orders.orderid,
xcart_orders.*
FROM xcart_orders
JOIN (
select count(*) as bad_statuses, userid from xcart_orders
where status in ('C','D')
group by userid
) bo
ON bo.userid=xcart_orders.userid
JOIN (
select count(*) as good_statuses, userid from xcart_orders
where status in ('A','B')
group by userid
) bo2
ON bo2.userid=xcart_orders.userid
WHERE bo2.good_statuses>0 and bo.bad_statuses=0
but think count(*) won't return zero for 'bad' statuses, so I get no results.
You have an aggregation without GROUP BY and for check the result you need us HAVING instead of WHERE
SELECT
xcart_orders.orderid,
xcart_orders.*,
SUM(CASE WHEN xcart_orders.status in ('C','D') THEN 1 ELSE 0 END) AS bad_statuses,
SUM(CASE WHEN xcart_orders.status in ('A','B') THEN 1 ELSE 0 END) AS good_statuses
FROM xcart_orders
GROUP BY orderid
HAVING bad_statuses = 0
AND good_statuses > 0
Please be aware the fields you get from xcart_orders.* will be random (or non deterministc) if you need a particular one you need to order it first.
First you GROUP BY user_id to check if have any status different to 'A', 'B'
Then you select orders from those user_id:
SQL DEMO
SELECT `user_id`
FROM orders1
GROUP BY `user_id`
HAVING COUNT(*) = COUNT(CASE WHEN `status` IN ('A', 'B') THEN 1 END);
SELECT *
FROM orders1
WHERE `user_id` IN (SELECT `user_id`
FROM orders1
GROUP BY `user_id`
HAVING COUNT(*) = COUNT(CASE WHEN `status` IN ('A', 'B') THEN 1 END)
);
OUTPUT
I have obtained two temporary tables which looks like follows:
Tmp1:
groups______active_members
a 2
b 3
c 7
Tmp2:
groups_______participants
a 1
b 2
c 4
I joined them with the code which looks like this:
SELECT
tmp1.group AS groups,
tmp1.active AS active_members,
tmp2.participiants
FROM(
(SELECT name AS 'group',
COUNT(`id`) AS 'active'
FROM table1
) tmp1
INNER JOIN
(SELECT name AS 'group',
COUNT(`id`) AS 'participiants'
FROM table2
) tmp2
ON tmp1.group=tmp2.group)
and obtained result like this:
groups___active_members___participants
a 2 1
b 3 2
c 7 4
I now want result as such:
groups___active_members___participants
a 2 1
b 3 2
c 7 4
Total 12 7
Please help !! I also tried using UNION and WITH ROLLUP but as I'm new, I became clueless.Any help would be highly appreciated.
SQL
SELECT tbl1.groups, tbl1.active_members, tbl2.participants
FROM tbl1
LEFT JOIN tbl2 ON tbl1.groups = tbl2.groups
UNION ALL
SELECT "Total", SUM(active_members), SUM(participants)
FROM (SELECT tbl1.groups, tbl1.active_members, tbl2.participants
FROM tbl1
LEFT JOIN tbl2 ON tbl1.groups = tbl2.groups) AS tmptbl;
Shema:
CREATE TABLE IF NOT EXISTS `tbl1` (
`id` int(11) NOT NULL,
`groups` char(11) NOT NULL,
`active_members` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `tbl2` (
`id` int(11) NOT NULL,
`groups` char(11) NOT NULL,
`participants` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
Result
SELECT groups,active_members,participiants FROM (
SELECT 0 AS ord, tmp1.group AS groups,
tmp1.active AS active_members,
tmp2.participiants
FROM(
(SELECT name AS 'group',
COUNT(`id`) AS 'active'
FROM table1
) tmp1
INNER JOIN
(SELECT name AS 'group',
COUNT(`id`) AS 'participiants'
FROM table2
) tmp2
ON tmp1.group=tmp2.group)
UNION ALL
SELECT 1 AS ord, 'TOTAL',
SUM(tmp1.active) AS active_members,
SUM(tmp2.participiants)
FROM(
(SELECT name AS 'group',
COUNT(`id`) AS 'active'
FROM table1
) tmp1
INNER JOIN
(SELECT name AS 'group',
COUNT(`id`) AS 'participiants'
FROM table2
) tmp2
ON tmp1.group=tmp2.group)
) AS tmp ORDER BY ord
This is my initial query:
SELECT bid_tag.*
FROM bid_tag join
(select serial_number, count(*) as cnt
from bid_tag where user_id = 0
group by serial_number
) tsum
on tsum.serial_number = bid_tag.serial_number and cnt > 1
order by bid_tag.serial_number
LIMIT 0, 21000;
Now from those results, I need to SELECT all where tag_design = 0 AND tag_size = 0 and then DELETE those records from the database.
I just don't know how to run a query on the results of an initial query.
Just replace SELECT with DELETE and it will delete the rows that would have been selected.
DELETE bid_tag.*
FROM bid_tag join
(select serial_number, count(*) as cnt
from bid_tag where user_id = 0
group by serial_number
) tsum
on tsum.serial_number = bid_tag.serial_number and cnt > 1
WHERE tag_design = 0 AND tag_size = 0
order by bid_tag.serial_number
LIMIT 0, 21000;
use an EXISTS term in your where clause:
DELETE
FROM bid_tag btd
WHERE EXISTS (
SELECT 1
FROM (
SELECT bid_tag.*
FROM bid_tag bts
JOIN (
SELECT serial_number, count(*) as cnt
FROM bid_tag btj
WHERE btj.user_id = 0
GROUP BY btj.serial_number
) tsum
ON ( tsum.serial_number = bts.serial_number
AND tsum.cnt > 1
)
WHERE bts.tag_design = 0
AND bts.tag_size = 0
ORDER BY bts.serial_number
LIMIT 0
, 21000
) rs_base
WHERE rs_base.id = btd.id -- PK column
)
;
the subquery in the EXISTS term can be nested further to contain another query on the result set of the original one. just make sure that you always select the primary key of the table on which the deletion is to be performed.
note that you probably don't want to restrict yourself to a part of your result set in a delete operation so check whether you need the limiting to the top 21000 results - if you dont, drop the 'ORDER BY' and 'LIMIT' clauses.
I have table psc_Pro_ProfessorPositions(ProfessorID,PositionID,StartDate,EndDate). It have 2 primary key is ProfessorID,PositionID.
I want to check ProfessorID,PositionID not in table to insert.I wrote like this:
insert into CoreUIs.dbo.psc_Pro_ProfessorPositions
(
ProfessorID,PositionID,StartDate,EndDate
)
select a.MaQuanLy,b.MaQuanLy,convert(smalldatetime,NgayHieuLuc),convert(smalldatetime,NgayHetHieuLuc)
from inserted
inner join GiangVien a on a.MaGiangVien = inserted.MaGiangVien
inner join ChucVu b on b.MaChucVu = inserted.MaChucVu
where a.MaQuanLy not in (select ProfessorID from CoreUIs.dbo.psc_Pro_ProfessorPositions)
and b.MaQuanLy not in (select PositionID from CoreUIs.dbo.psc_Pro_ProfessorPositions)
But it's wrong.Can help me?Thanks all.
;WITH x AS
(
SELECT TeacherID, ClassID, ClassStuID, s = [SUM],
rn = ROW_NUMBER() OVER (PARTITION BY TeacherID ORDER BY ClassID)
FROM dbo.TB1
)
SELECT TeacherID, ClassID, ClassStuID,
[SUM] = CASE rn WHEN 1 THEN s ELSE NULL END
FROM x
ORDER BY TeacherID, [SUM] DESC;
You can employ CTEs with ROW_NUMBER()OVER() to identify the first row of each TeacherID:
; with a as (
select * from TB1
union
select * from TB2
)
, b as (
select *, r=ROW_NUMBER()over(partition by a.TeacherID order by a.TeacherID,
a.ClassID, a.ClassStuID) from a
)
select b.TeacherID, b.ClassID, b.ClassStuID
, [SUM]=case b.r when 1 then b.[SUM] else null end
from b
order by b.TeacherID, b.r
go
Result: