T-SQL Query not bringing back a count of 0 - tsql

I have a feeling I am making some sort of foolish mistake here, however I am trying to do a query over two tables. One table contains the value I want to aggregate over, in this case I have called if the StoreCharge table. The other table contains the values I want to count.
SELECT StoreCharge.StoreId,
COUNT(DISTINCT(ISNULL(WholesalerInvoice.WholesalerId,0))) AS Invoices
FROM StoreCharge
LEFT OUTER JOIN
WholesalerInvoice ON StoreCharge.StoreId = WholesalerInvoice.StoreId
WHERE StoreCharge.CompanyId = 2
AND WholesalerInvoice.StoreInvoiceId IS NULL
AND DATEDIFF(day,WholesalerInvoice.InvoiceDate,'20100627') > =0
AND DATEDIFF(day,dateadd(day,-7,'20100627'),WholesalerInvoice.InvoiceDate) > 0
GROUP BY StoreCharge.StoreId
My problem is that if there are rows in the counting table that match the WHERE clause, the query works ok. However When no rows match the criteria nothing is returned instead of a list of the values in StoreCharge with a count of 0.

WHERE is evaluated after the LEFT OUTER JOIN
Try moving your WHERE filter related to WholesalerInvoice into the OUTER JOIN
SELECT StoreCharge.StoreId,
COUNT(DISTINCT(ISNULL(WholesalerInvoice.WholesalerId,0))) AS Invoices
FROM StoreCharge
LEFT OUTER JOIN
WholesalerInvoice ON StoreCharge.StoreId = WholesalerInvoice.StoreId
AND DATEDIFF(day,WholesalerInvoice.InvoiceDate,'20100627') > =0
AND DATEDIFF(day,dateadd(day,-7,'20100627'),WholesalerInvoice.InvoiceDate) > 0
WHERE StoreCharge.CompanyId = 2
GROUP BY StoreCharge.StoreId
This will filter the required WholesalerInvoice records out and leave the StoreCharge table intact.

Based on the query in the example, you don't actually use what you join in. Unless there is more to the query a Subquery would produce the desired result.
SELECT StoreCharge.StoreId,
(SELECT COUNT(0) FROM WholesalerInvoice WHERE WholesalerInvoice.StoreId = StoreCharge.StoreId
AND DATEDIFF(day,WholesalerInvoice.InvoiceDate,'20100627') > =0
AND DATEDIFF(day,dateadd(day,-7,'20100627'),WholesalerInvoice.InvoiceDate) > 0) [Invoices]
FROM StoreCharge
WHERE StoreCharge.CompanyId = 2

Related

How can I list other matching values ​even if there is an unmatched value in the query?

In my query there is a value that will not match in the demand category table. Therefore, since one value does not match in the output of my query, other matching values ​​do not appear.
I want to do;
How can I list other matching values ​​even if there is an unmatched value in the query?
process Table
fk_unit_id fk_unit_position fk_demand_category
1 2 1
unit table
unit_id
1
unit_position table
unit_position
2
demand_category table
demand_category
1
Query:
SELECT unit_name,unit_position_name,demand_category_name From process
INNER JOIN unit ON process.fk_unit_id = unit_id and unit_id =1
INNER JOIN unit_position ON process.fk_unit_position_id = unit_position_id and unit_position_id = 2
INNER JOIN demand_category ON process.fk_demand_category_id = demand_category_id and demand_category_id =0 ;
Switch INNER JOIN on demand_category with LEFT JOIN
LEFT JOIN gets all records from the LEFT linked and the related record from the right table ,but if you have selected some columns from the RIGHT table, if there is no related records, these columns will contain NULL.
SELECT unit_name,unit_position_name,demand_category_name From process
INNER JOIN unit ON process.fk_unit_id = unit_id and unit_id =1
INNER JOIN unit_position ON process.fk_unit_position_id = unit_position_id and unit_position_id = 2
LEFT JOIN demand_category ON process.fk_demand_category_id = demand_category_id and demand_category_id =0 ;
You can use outer join to have the columns that don't match, just the corresponding values in other table will be padded with null. Other way is to use IN operator, but slower query performance.

Using two COUNT in SELECT returns the same values

SELECT user_posts.id,
COUNT(user_post_comments.post_id) as number_of_comments,
COUNT(user_post_reactions.post_id) as number_of_reactions
FROM user_posts
LEFT JOIN user_post_comments
ON (user_posts.id = user_post_comments.post_id)
LEFT JOIN user_post_reactions
ON (user_posts.id = user_post_reactions.post_id)
WHERE user_posts.user_id = '850e6511-2f30-472d-95a1-59a02308b46a'
group by user_posts.id
I have this query for getting the number of comments and reactions from another table by post_id
current output screenshot
To caluclate number of comments and reactions just use subqueries. No need to join and group by.
SELECT user_posts.id,
( select COUNT(*) from user_post_comments
where user_posts.id = user_post_comments.post_id
) as number_of_comments,
( select COUNT(*) from user_post_reactions
where user_posts.id = user_post_reactions.post_id
) as number_of_reactions
FROM user_posts
WHERE user_posts.user_id = '850e6511-2f30-472d-95a1-59a02308b46a'
If both joins return non-null rows, what you get for each count is the product of the number of rows from each for a given user_posts.id. One way you could fix that is by counting distinct identifiers for each table, e.g.
COUNT(DISTINCT user_post_comments.id) as number_of_comments
(Assuming "id" exists as a primary key on that table). This may not be spectacularly efficient, but is relatively simple.

How to make postgres (cursor?) start at particular row

I have created the following query:
select t.id, t.row_id, t.content, t.location, t.retweet_count, t.favorite_count, t.happened_at,
a.id, a.screen_name, a.name, a.description, a.followers_count, a.friends_count, a.statuses_count,
c.id, c.code, c.name,
t.parent_id
from tweets t
join accounts a on a.id = t.author_id
left outer join countries c on c.id = t.country_id
where t.row_id > %s
-- order by t.row_id
limit 100
Where %s is a number that starts at 0 and is incremented by 100 after each such query is conducted. I want to fetch all records from the database using this method, where I just increase the %s in the where condition. I found this approach on https://ivopereira.net/efficient-pagination-dont-use-offset-limit. I also included a column in my table which is corresponding to row number (I named it row_id). Now the problem is when I run this query the first time, it returns rows which have an row_id of 3 million. I would like the cursor (not sure if my terminology is correct) to start from rows with row_id 1 through 100 and so on. The table contains 7 million rows. Am I missing something obvious with which I could achieve my goal?

How to count total number of records after join the three tables in postgresql?

I have a query which gives me total 12408 records after executing but i want this give me total records as count column
select
c.complaint_id,c.server_time,c.completion_date,c.road_id,c.photo,c.dept_code,c.dist_code,c.eng_userid,c.feedback_type,c.status,p.dist_name,p.road_name,p.road_dept,e.display_name,e.mobile
from complaints as c INNER JOIN pwd_roads as p ON p.road_id=c.road_id
INNER JOIN enc_details as e ON CAST(e.enc_code as INTEGER) = p.enccode
where c.complaint_id=c.parent_complaint_id and c.dept_code='PWDBnR'
and c.server_time between '2018-09-03' and '2018-12-19'
You can solve this issue using window functions. For example, if you want your first columns to be a count of the total rows done by the SELECT statement:
select count(1) over(range between unbounded preceding and unbounded following) as total_row_count
, c.complaint_id,c.server_time,c.completion_date,c.road_id,c.photo,c.dept_code,c.dist_code,c.eng_userid,c.feedback_type,c.status,p.dist_name,p.road_name,p.road_dept,e.display_name,e.mobile from complaints as c INNER JOIN pwd_roads as p ON p.road_id=c.road_id INNER JOIN enc_details as e ON CAST(e.enc_code as INTEGER) = p.enccode where c.complaint_id=c.parent_complaint_id and c.dept_code='PWDBnR' and c.server_time between '2018-09-03' and '2018-12-19'
Note that the window function is evaluated before the LIMIT clause if one is used, so if you were to add LIMIT 100 to the query it might give a row count greater than 100 even though a max of 100 rows would be returned.
Easiest but not very elegant way to do this is:
select count(*)
from
(
select c.complaint_id,c.server_time,c.completion_date,c.road_id,c.photo,c.dept_code,c.dist_code,c.eng_userid,c.feedback_type,c.status,p.dist_name,p.road_name,p.road_dept,e.display_name,e.mobile from complaints as c INNER JOIN pwd_roads as p ON p.road_id=c.road_id INNER JOIN enc_details as e ON CAST(e.enc_code as INTEGER) = p.enccode where c.complaint_id=c.parent_complaint_id and c.dept_code='PWDBnR' and c.server_time between '2018-09-03' and '2018-12-19'
)

T-SQL query one table, get presence or absence of other table value

I'm not sure what this type of query is called so I've been unable to search for it properly. I've got two tables, Table A has about 10,000 rows. Table B has a variable amount of rows.
I want to write a query that gets all of Table A's results but with an added column, the value of that column is a boolean that says whether the result also appears in Table B.
I've written this query which works but is slow, it doesn't use a boolean but rather a count that will be either zero or one. Any suggested improvements are gratefully accepted:
SELECT u.number,u.name,u.deliveryaddress,
(SELECT COUNT(productUserid)
FROM ProductUser
WHERE number = u.number and productid = #ProductId)
AS IsInPromo
FROM Users u
UPDATE
I've run the query with actual execution plan enabled, I'm not sure how to show the results but various costs are:
Nested Loops (left semi join): 29%]
Clustered Index scan (User Table): 41%
Clustered Index Scan (ProductUser table): 29%
NUMBERS
There are 7366 users in the users table and currently 18 rows in the productUser table (although this will change and could be in the thousands)
You can use EXISTS to short circuit after the first row is found rather than COUNT-ing all matching rows.
SQL Server does not have a boolean datatype. The closest equivalent is BIT
SELECT u.number,
u.name,
u.deliveryaddress,
CASE
WHEN EXISTS (SELECT *
FROM ProductUser
WHERE number = u.number
AND productid = #ProductId) THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT)
END AS IsInPromo
FROM Users u
RE: "I'm not sure what this type of query is called". This will give a plan with a semi join. See Subqueries in CASE Expressions for more about this.
Which management system are you using?
Try this:
SELECT u.number,u.name,u.deliveryaddress,
case when COUNT(p.productUserid) > 0 then 1 else 0 end
FROM Users u
left join ProductUser p on p.number = u.number and productid = #ProductId
group by u.number,u.name,u.deliveryaddress
UPD: this could be faster using mssql
;with fff as
(
select distinct p.number from ProductUser p where p.productid = #ProductId
)
select u.number,u.name,u.deliveryaddress,
case when isnull(f.number, 0) = 0 then 0 else 1 end
from Users u left join fff f on f.number = u.number
Since you seem concerned about performance, this query can perform faster as this will cause index seek on both tables versus an index scan:
SELECT u.number,
u.name,
u.deliveryaddress,
ISNULL(p.number, 0) IsInPromo
FROM Users u
LEFT JOIN ProductUser p ON p.number = u.number
WHERE p.productid = #ProductId