query make a count to 1 which does not satistfy the condition - mysql

i have a two table i want to know the number of person who are all assigned to project in each sector
CREATE TABLE first1( a int,projectname varchar(20));
INSERT INTO first1 VALUES
(1001,'crm'),
(1002,'iic'),
(1003,'abc'),
(1004,'sifty bank');
CREATE TABLE diff(b int,name varchar(20),p_id int );
INSERT INTO diff VALUES
(101,'priya',1001),
(102,'divya',1002),
(103,'sidhu',null),
(104,'shiva',null),
(105,'surya',1002);
Query:
select first1.projectname,count(*) from first1 left join diff on first1.a=diff.p_id group by
first1.projectname;
The output of this code is:
abc|1
crm|1
iic|2
sifty bank|1
The expected output is :
abc|0
crm|1
iic|2
sifty bank|0

The problem is count(*); it counts how many rows there are in each group - A project without any person assigned still counts as 1. Instead, you need to count() something from the left table, so null values are not taken into account:
select f.projectname, count(d.p_id) as cnt_diff
from first1 f
left join diff d on f.a = d.p_id
group by f.projectname;
Note that you can get the same result with a subquery:
select f.projectname,
(select count(*) from diff d where d.p_id = f.a) as cnt_diff
from first1 f

Related

sql tables to find top 5 male and top 5 female purchase using data stored in two different tables and gender in one table and purchse in another table

CREATE TABLE mutual_fund (
transaction_id INTEGER(40),
customer_id INTEGER(40),
transaction_type ENUM('Purchase','Sale'),
nav_value INTEGER(40),
no_of_units INTEGER(40),
transaction_time TIMESTAMP,
transaction_status ENUM('Success','Failed','Pending')
);
INSERT INTO mutual_fund (transaction_id,customer_id,transaction_type,nav_value,no_of_units,transaction_time,transaction_status)
VALUES (1200,11,'Sale',3000,13,'2019-04-01 12:28:05','Success'),
(1201,12,'Purchase',6000,6,'2019-04-17 14:54:10','Failed'),
(1202,13,'Sale',2000,20,'2019-01-19 16:41:12','Failed'),
(1203,14,'Purchase',3400,11,'2019-01-27 20:08:45','Success'),
(1204,15,'Sale',7000,5,'2019-04-27 14:38:45','Success'),
(1205,16,'Purchase',1000,10,'2019-04-01 09:28:55','Success'),
(1206,17,'Sale',20000,12,'2019-01-29 19:01:32','Success'),
(1207,18,'Purchase',8000,5,'2021-01-26 11:57:02','Success'),
(1208,19,'Purchase',10000,3,'2021-01-26 12:34:53','Success'),
(1209,20,'Purchase',9000,9,'2021-04-26 16:13:18','Success'),
(1210,21,'Sale',19000,9,'2021-04-26 11:03:19','Failed');
CREATE TABLE customer_details (
customer_id INTEGER(40),
customer_name CHARACTER VARYING(40),
customer_PAN CHAR(40),
banned BOOLEAN,
customer_join_time TIMESTAMP,
gender ENUM('Male','Female')
);
INSERT INTO customer_details(customer_id,customer_name,customer_PAN,banned,customer_join_time,gender)
VALUES (11,'salil','sa11',0,'2019-04-01','Male'),
(12,'puran','pu12',1,'2019-04-17','Male'),
(13,'saumya','sa12',1,'2019-01-19','Female'),
(14,'priya','pr11',0,'2019-01-27','Female'),
(15,'suresh','su15',0,'2019-04-27','Male'),
(16,'amit','am11',0,'2019-04-01','Male'),
(17,'rahul','ra45',0,'2019-01-29','Male'),
(18,'rajesh','ra21',0,'2021-01-26','Male'),
(19,'aswini','as65',0,'2021-01-26','Female'),
(20,'prabha','pr95',0,'2021-04-26','Female'),
(21,'shubham','sh01',1,'2021-04-26','Male');
SELECT c.customer_id,c.gender,m.nav_value,m.transaction_type,m.transaction_status
FROM customer_details c
INNER JOIN mutual_fund m on c.customer_id=m.customer_id
WHERE (SELECT c.gender='Male' FROM customer_details c INNER JOIN mutual_fund m on c.customer_id=m.customer_id ORDER BY m.nav_value DESC LIMIT 5) AS t1
UNION ALL
(SELECT c.gender="Female" FROM customer_details c INNER JOIN mutual_fund m on c.customer_id=m.customer_id ORDER BY m.nav_value DESC LIMIT 5) AS t2;
i am trying find out the top 5 male and top 5 female purchases(nav_value) but i am stuck here
as gender is in customer_detail table and purchase(nav_value) is on mutual_fund table so using inner join and then thought union will work but i am stuck here and got no ideas left so any ideas people can this work ??????
You could go with something like this:
SELECT *
FROM
(
SELECT c.customer_id,c.gender,m.nav_value,m.transaction_type,m.transaction_status,
RANK() OVER (PARTITION BY c.gender ORDER BY m.nav_value DESC) AS RNum
FROM customer_details c
INNER JOIN mutual_fund m on c.customer_id=m.customer_id
) t
WHERE Rnum <= 5
You can read more about window functions here. You might want to go with one of the other window functions though, like DENSE_RANK or ROW_NUMBER depending on your needs.

How to obtain data from sub query that has self join?

my table:
friends(uid_1 int, uid_2 int)
This is my query :
SELECT a.uid_1
, a.uid_2 as a2
, b.uid_1 as b1
, b.uid_2
from friend a
join friend b
on a.uid_1 = b.uid_2;
I want to obtain a2 and b1 from query for other purposes
So this query now:
Select a2,b1
from (SELECT a.uid_1,a.uid_2 as a2,b.uid_1 as b1,b.uid_2
from friend a join
friend b
on a.uid_1=b.uid_2
)
does not work. How do I obtain certain data from a range of displayed data?
Number 1, you are just missing with a Alias name for your sub query as below-
Select a2,b1
from (
SELECT a.uid_1,a.uid_2 as a2,b.uid_1 as b1,b.uid_2
from friend a join
friend b
on a.uid_1=b.uid_2
) A -- added A as a Alias
But number 2, not sure what you are trying to do with the JOIN as your query with implemented JOIN conditions is simply equivalent to below query-
SELECT *
FROM friend
WHERE uid_1 = uid_2
You need table name alias for the subquery eg : Select ... FROM (subquery ) T
then you can refer the subquery content with a fully qualified name
Select T.a2, T.b1
from (SELECT a.uid_1,a.uid_2 as a2, b.uid_1 as b1, b.uid_2 b2
from friend a join
friend b
on a.uid_1=b.uid_2
) T
You were just missing alias
Select a2,b1
from (SELECT a.uid_1,a.uid_2 as a2,b.uid_1 as b1,b.uid_2
from friend a join
friend b
on a.uid_1=b.uid_2
) as temp -- here it is

get updated date field row after inner joining table

I have a situation where a row is inserted whenever a schedule is created with call_back_date value
la_id is the same for each row, i want get a most recent row that is max(call_back_date)
I have written this query which fetch all the entries for those schedule after inner joining three tables:
SELECT
la_details.application_no,
la_details.id la_det,
la_details.client_id client_id,
la_details.la_name la_name,
la_details.sex sex,
la_details.advisor_name advisor_name,
la_details.client_phone client_phone,
la_details.client_mobile client_mibile,
la_details.level level,
la_details.state state,
la_details.pin_code pin_code,
trans_schedules.id schedule_id,
trans_schedules.*,
comments.descriptions
FROM
la_details
INNER JOIN trans_schedules
ON
trans_schedules.la_id=la_details.id
INNER JOIN comments
ON
comments.comment_id=trans_schedules.comment_id
WHERE
(trans_schedules.comment_id<>'1'
OR
trans_schedules.list_followup = '1'
OR
trans_schedules.counter_flag='0')
AND
la_details.case_closed='0'
ORDER BY
trans_schedules.call_back_date
) a1 INNER JOIN
(
SELECT la_id,MAX(call_back_date) AS call_back_date from
trans_schedules group by la_id
) b1 on a1.la_det = b1.la_id and a1.call_back_date = b1.call_back_date
My question is how could i use a subquery on previous query to get max call_back_date row
Thanks in advance for help!!!!
For MySQL:
Select LAST_INSERT_ID();
It will give you last inserted identity record

SQL select rows that have one value but not another

I have a table in SQL which will contain multiple rows for one id, as below
accountid Productname
1 GL
1 IP
1 MI
2 GL
2 IP
2 PA
3 MI
3 CP
3 IP
4 GL
4 CP
4 CI
I want to be able to select all accounts which have certain products but not other. For example all that have IP or GL but not MI, using the sample table above this would return accounts 2 and 4.
SELECT ccx_accountidname
FROM (
SELECT ccx_accountidname, ccx_productname
FROM Filteredccx_leadresearch
WHERE ccx_productname IN ('GL','IP')
AND ccx_accountidname IS NOT NULL
) AS T
WHERE ccx_productname NOT IN ('MI')
ORDER BY ccx_accountidname
and
SELECT DISTINCT LR1.ccx_accountidname
FROM Filteredccx_leadresearch LR1
LEFT JOIN Filteredccx_leadresearch LR2 ON LR1.ccx_accountid = LR2.ccx_accountid
AND LR2.ccx_productname IN ('GL', 'IP')
WHERE LR1.ccx_productname NOT IN ('MI')
AND LR1.ccx_accountidname IS NOT NULL
ORDER BY LR1.ccx_accountidname
Both give basically the same results, is there any way this can be done?
Thanks in advance for any help
Could you try this:
SELECT DISTINCT T1.Accountidname FROM TheTableThatContainsAccountnames as T1
JOIN AccountProductsTable as T2 on T1.AccountId=T2.AccountId
WHERE T2.ProductName = 'ProductYouWant'
AND T2.ProductName = 'AnOtherProductYouWant'
According to your post, all you really need is a simple query with the correct and logic. You want all accounts with Product name GL or IP but not in MI. This will do it without any other joins.
SELECT ccx_accountidname
FROM Filteredccx_leadresearch
WHERE
ccx_productname in ('GL','IP')
and ccx_productname not in ('MI')
EDIT
This will get you the account, though I doubt it will work in your overall solution. It's just hard to tell without seeing your complete dataset. This could be done with parameters too.
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
DROP TABLE #TempTable
IF OBJECT_ID('tempdb..#TempTableTwo') IS NOT NULL
DROP TABLE #TempTableTwo
create table #TempTable (accountid int, productname char(2))
insert into #TempTable (accountid,productname) values
(1,'GL'),
(1,'IP'),
(1,'MI'),
(2,'GL'),
(2,'IP'),
(2,'MA')
select distinct
t1.accountid,
1 as T
into #TempTableTwo
from
#TempTable t1
where
productname in ('GL','IP')
union all
select distinct
t1.accountid,
-1 as T
from
#TempTable t1
where
productname in ('MI')
select
accountid
from #TempTableTwo
group by accountid
having sum(T) > 0
I might be late for the game, but this should do the trick, if anyone is trying to solve a similar problem. I renamed your table and it's columns:
Filteredccx_leadresearch -> l_search
ccx_accountidname -> a_name
ccx_productname -> p_name
And here's the SQL:
(SELECT DISTINCT t1.a_name
FROM l_search t1
JOIN l_search t2 ON t1.a_name = t2.a_name
WHERE t1.p_name = 'IP'
OR t2.p_name = 'GL')
MINUS
(SELECT DISTINCT t1.a_name
FROM l_search t1
JOIN l_search t2 ON t1.a_name = t2.a_name
WHERE ((t1.p_name = 'IP'OR t1.p_name = 'GL') AND t2.p_name = 'MI')
OR
(t1.p_name = 'MI' AND (t1.p_name = 'IP' OR t1.p_name = 'GL')));
First set:
cross product of table on itself with same IDs, get account IDs which have a product 'IP' or 'GL'.
Second set:
cross product of table on itself with same IDs, get account IDs which have p_name ('IP' OR 'GL') on first cross property AND 'MI' on second.
Also, get those IDs, which have the same but the other way around: p_name 'MI' on first cross property AND ('IP' OR 'GL') on second.
And finally subtract the second from the first.
Here is a simple way to include the accounts that match either IP or GL and exclude those accounts if they have an record for MI without using a subquery.
This is assuming t1 is a table that has unique account numbers in accountid and t2 is the table you have shown above that has accountid and Productname columns.
SELECT DISTINCT
t1.accountid
FROM t1
LEFT JOIN t2 AS t2_match
ON t1.accountid = t2_match.accountid
AND
(
t2_match.Productname = 'IP'
OR t2_match.Productname = 'GL'
)
LEFT JOIN t2 AS t2_not_match
ON t1.accountid = t2_not_match.accountid
AND t2_not_match.Productname = 'MI'
WHERE
t2_match.accountid IS NOT NULL
AND t2_not_match.accountid IS NULL
This is really late, but it might help some one.
I'll focus only on using the columns we have on the table we are shown (won't combine it with other tables we were not given).
Since the only table in the example is not clearly named, I'll call it some_table
SELECT t.accountidname, t.productname
FROM some_table t
WHERE t.productname IN ('GL','IP')
AND t.accountidname NOT IN (
SELECT accountidname
FROM some_table
WHERE productname = 'MI'
);
The idea here is to:
Select all accountid and productname that have productname either GL or IP (3rd line)
Select all accountid that have a productname MI and remove them from the values we already have (4th line onwards)
With this values, filtering or combining it with other tables should be rather trivial.
You might want to replace the SELECT with SELECT DISTINCT if the combinations of accountid and productname could be repeated in the table.

Inner query is difficult to write

I have two tables:
customer with schema_id
Schema table has: schema_id, period, amt, updated_date
I need to take join of customer and schema but only retrieve the latest record joined and not the others.
customer table
cust_id name schema_id
1 ABC 1
Schema table
schema_id period amt updated_date
1 1 100 2010-4-1
1 2 150 2011-4-1
If you need the max(updated_date) for each schema_id, then you can use an subquery:
select c.cust_id, c.name, c.schema_id, s.period, s.amt, s.updated_date
from customer c
inner join
(
select s1.schema_id, s1.period, s1.amt, s1.updated_date
from `schemas` s1
inner join
(
select schema_id, max(updated_date) MaxDate
from `schemas`
group by schema_id
) s2
on s1.schema_id = s2.schema_id
and s1.updated_date = s2.maxdate
) s
on c.schema_id = s.schema_id
See SQL Fiddle with Demo
The subquery is then used in a join back to your table to return the rows that have the matching date and schema_id.
If I understood your problem, you need to take lastest register of the "schema".
I think you need to use max() function. So, try the query below:
select *
from customer c,
schema s
where c.schema_id = s.schema_id
and s.updated_date = ( select max(s2.updated_date)
from schema s2
where s2.schema_id = s.schema_id
)
Regards!
Edmilton