SQL QUERY data reading - sql

I have two table country and Users. I want to view the country name which have user disabled. So i wrote query for this.
SELECT DISTINCT cntr_id,cntr_name FROM
(SELECT COUNTRY.cntr_id, COUNTRY.cntr_name, USERS.user_enabled,
USERS.user_name, USERS.user_id
FROM COUNTRY INNER JOIN Users
ON COUNTRY.cntr_id = USERS.cntr_id
)
AS TAB where user_enabled = 0
My questions are :
Is this inner query?
will the query fetch all the countries (include user enabled) from the database before running outer query?
Is there any other method to select?

Yes it's an inner Query and will fetch what you need, but you don't need your outer SELECT query. You could just do it like:
SELECT DISTINCT COUNTRY.cntr_id, COUNTRY.cntr_name
FROM COUNTRY INNER JOIN Users
ON COUNTRY.cntr_id = USERS.cntr_id
WHERE USERS.user_enabled = 0

Yes, that is inner query.
Yes, inner query will fetch all the countries (including user enabled). Outer query will remove those records later.
You don't have to use outer query for this.
SELECT DISTINCT C.cntr_id, C.cntr_name
FROM COUNTRY C INNER JOIN
Users U ON C.cntr_id = U.cntr_id
WHERE U.user_enabled=0
OR
SELECT C.cntr_id, C.cntr_name
FROM COUNTRY C INNER JOIN
Users U ON C.cntr_id = U.cntr_id
WHERE U.user_enabled=0
GROUP BY C.cntr_id, C.cntr_name

To answer your question,
Yes It is inner and outer two queries.
The inner query will fetch the all rows which satisfy the join condition.
Yes there is other method to select where you can directly apply the filter in inner query and remove the outer select.
SELECT COUNTRY.cntr_id, COUNTRY.cntr_name, USERS.user_enabled,
USERS.user_name, USERS.user_id
FROM COUNTRY INNER JOIN Users
ON COUNTRY.cntr_id = USERS.cntr_id
WHERE
USERS.user_enabled = 0

Related

Join with count

I need to write SQL query like:
Show all countries with more than 1000 users, sorted by user count.
The country with the most users should be at the top.
I have tables:
● Table users (id, email, citizenship_country_id)
● Table countries (id, name, iso)
Users with columns: id, email, citizenship_country_id
Countries with columns: id, name, iso
SELECT countries.name,
Count(users.citiizenship_country_id) AS W1
FROM countries
LEFT JOIN users ON countries.id = users.citizenship_country_id
GROUP BY users.citiizenship_country_id, countries.name
HAVING ((([users].[citiizenship_country_id])>2));
But this does not work - I get an empty result set.
Could you please tell me what I'm doing wrong?
A LEFT JOIN is superfluous for this purpose. To have 1000 users, you need at least one match:
SELECT c.name, Count(*) AS W1
FROM countries c JOIN
users u
ON c.id = u.citizenship_country_id
GROUP BY c.name
HAVING COUNT(*) > 1000;
Notice that table aliases also make the query easier to write and to read.
Group by country name and use HAVING Count(u.citiizenship_country_id)>1000, it filters rows after aggregation:
SELECT c.name,
Count(u.citiizenship_country_id) AS W1
FROM countries c
INNER JOIN users u ON c.id = u.citizenship_country_id
GROUP BY c.name
HAVING Count(u.citiizenship_country_id)>1000
ORDER BY W1 desc --Order top counts first
;
As #GordonLinoff pointed, you can use INNER JOIN instead of LEFT JOIN, because anyway this query does not return counries without users and INNER JOIN performs better because no need to pass not joined records to the aggregation.

How to use outer query column inside inner query column

I am trying to run postgresql query below
SELECT *
FROM user_follow uf
INNER JOIN (SELECT uplr.post, COUNT(*)
FROM user_post_like_relation uplr
WHERE uplr.category = 'like' AND uf.recently_viewed < uplr.created_at . //CANNOT reference uf
AND clicked = true
GROUP BY uplr.post) uplr
ON uplr.post = uf.post
INNER JOIN post p ON uf.post = p.id
Unfortunately I am not able to reference uf inside the INNER JOIN query but it is essential that I join and also reference the recently_viewed column in side the JOIN query. Is there a way of overcoming this?
I think it is sufficient in your case to just JOIN to the table and GROUP the results to perform COUNT.
SELECT uf.post, p.id, count(*)
FROM user_follow uf
JOIN post p ON uf.post = p.id
JOIN user_post_like_relation uplr ON uplr.post = uf.post
WHERE uplr.category = 'like'
AND clicked = 'true'
AND uf.recently_viewed < uplr.created_at
GROUP BY uf.post, p.id
Play with SELECT and GROUP BY columns to get ones which you need.
You have to use INNER JOIN LATERAL if you want to reference columns from previous FROM list entries.
This is available from PostgreSQL 9.3 on.

Fetch rows and count them in sqlserver

I wrote a stored procedure that join three tables to fetch province title from it's table. This is my code:
BEGIN
select TbProvince.title, count(TbProvince.title) as cnt
from TbProvince
where TbProvince.provinceId IN (select TbCustomerUser.provinceId
from TbCustomerUser INNER JOIN
TbDeals
on TbCustomerUser.UserId = TbDeals.sellerUserID
where TbDeals.buyerUserID = 1
)
group by TbProvince.title
end
Description: I have three tables for deals, customers and provinces. I want to retrieve province title and the count of that for customers that were sellers.
The above code have no problem, but only return 1 as a count. The number of customers is more than one.
Can anybody help me solve my problem?
Your query is filtering the rows of TbProvince and then aggregating that table -- and only that table.
Instead, you want to join the tables together to count the customers not the provinces. The query is much simpler to write and read if you use table aliases:
select p.Title, count(*)
from TbCustomerUser cu join
TbDeals d
on cu.UserId = d.sellerUserID join
TbProvince p
on p.provinceId = cu.provinceId
where d.buyerUserID = 1
group by p.Title;
You have to perform the JOIN with customer table. If you use semi join (expressed by IN construct in your case) then you avoid duplicates that are expected in your case.
SELECT TbProvince.title,
COUNT(TbProvince.title) AS cnt
FROM TbProvince
JOIN TbCustomerUser ON TbProvince.provinceId = TbCustomerUser.provinceId
JOIN TbDeals ON TbCustomerUser.UserId = TbDeals.sellerUserID
WHERE TbDeals.buyerUserID = 1
GROUP BY TbProvince.title;
It should be as simple as:
You won't need the subselect. Just join all three tables and you'll receive your desired result.
SELECT TbProvince.title,
count(TbProvince.title) as cnt
FROM TbProvince
INNER JOIN TbCustomerUser
ON TbProvince.provinceId = TbCustomerUser.provinceId
INNER JOIN TbDeals
ON TbCustomerUser.UserId = TbDeals.sellerUserID
AND TbDeals.buyerUserID = 1
GROUP BY TbProvince.title
Why did your solution not work?
You subselect will return a "list" of provinceIDs from TbCustomerUser combinated with TbDeals with your restriction TbDeals.buyerUserID = 1.
The outer select will now return all rows from TbProvince IN this list.
But it's not returning a row for each Customer who had a deal.
That's why you have to JOIN all three tables at once.

Transact SQL JOIN

I have the following query:
SELECT MS.idReg, MS.dsMotivo, A.contrato FROM MS
INNER JOIN S
ON S.motivoSiniestro = MS.idReg
INNER JOIN C
ON C.n__contrat = S.n__contrat
INNER JOIN A
ON A.n__article = C.n__article
Table MS has only 12 records, the ones I need and others have many more entries.
My problem is that I only want the 12 records from MS and their contrato column but I'm getting much more that that. Have tried many combinations of INNER, OUTER, LEFT and RIGHT joins. Any help?
You get too many records because there are several A.contrato values for each row in the MS table. Sql server does not know which one of all the A.contrato values to take so it returns all of them. First you need to decide which one you want.
If any will do you can simply write your query like this:
SELECT MS.idReg, MS.dsMotivo, MAX(A.contrato)
FROM MS
INNER JOIN S
ON S.motivoSiniestro = MS.idReg
INNER JOIN C
ON C.n__contrat = S.n__contrat
INNER JOIN A
ON A.n__article = C.n__article
GROUP BY MS.idReg, MS.dsMotivo
Try this one -
SELECT MS.idReg, MS.dsMotivo, A.contrato
FROM dbo.MS
OUTER APPLY (
SELECT TOP 1 A.contrato
FROM dbo.S
JOIN dbo.C ON C.n__contrat = S.n__contrat
JOIN dbo.A ON A.n__article = C.n__article
WHERE S.motivoSiniestro = MS.idReg
) s

How to make this join with a TSQL query?

I have a table called USERS that has a foreign key to the table GROUPS (a user can pertain to one or none GROUPS). The table USERS also contains a column ISDELETED (a char column with T or F).
I need a query to retrieve all the GROUPS and all the USERS that are not deleted, if all the users in a GROUP are deleted or no users are defined I need the query to return NULL for that GROUP.
I tried with the following query:
SELECT GROUPS.*, USERS.*
FROM GROUPS INNER JOIN
USERS ON GROUPS.ID = USERS.GROUPID
WHERE USERS.ISDELETED = 'F'
But this query does not returns the groups that are empty. SQL and me are not the best friends in world, some help will be great, thanks.
If you want all the groups, regardless of a match in the users table, you should use a left outer join:
SELECT GROUPS.*, USERS.*
FROM GROUPS
LEFT OUTER JOIN
USERS
ON GROUPS.ID = USERS.GROUPID AND USERS.ISDELETED = 'F'
You should just need to do a left outer join -
SELECT GROUPS.*, USERS.*
FROM GROUPS LEFT OUTER JOIN
USERS ON GROUPS.ID = USERS.GROUPID
WHERE USERS.ISDELETED = 'F'
Here's a reference I like to use to remind myself of the differences in sql joins.
You need to use the LEFT OUTER JOIN operator instead of the INNER JOIN.