SQL subtraction across two tables when two tables does not match - sql-server

I have two SQL select queries which return two columns as you can see in the image below. What I want to do is subtract second query's UnsuppliedQty from the first query's relevant stock code's Total column.
Could you guide me the different approaches to do it in here.
Update: Using the query below, I was able to perform the subtraction, however it gives null when the where clause does not match with first table. In this case, I want to return the original value it had.
How do I do it?
select stockcode, totalstock -(
select UNSUP_QUANT
from SALESORD_LINES
where stockcode='AIRFIL01'
and UNSUP_QUANT<>0
and dbo.STOCK_ITEMS.STOCKCODE = SALESORD_LINES.STOCKCODE)
from STOCK_ITEMS

You may use a simple Join, Like this
;WITH SL
AS
(
SELECT
StockCode,
UNSUP_QUANT = SUM(ISNULL(UNSUP_QUANT,0.00))
FROM SALESORD_LINES
WHERE ISNULL(UNSUP_QUANT,0.00) <> 0
GROUP BY StockCode
)
SELECT
SL.StockCode,
TotalStock = SI.TotalStock - SL.UNSUP_QUANT
FROM STOCK_ITEMS SI
LEFT JOIN SL
ON SL.StockCode = SI.StockCode

Related

t-sql long query using CTE's and cross joins

I'm facing a very weird problem where I have a complex (long) query with multiple CTE's and in the end I select values from those multiple CTE's using cross joins. Most of the time it works fine, but for some cases it's returning 0 zeros where it should return data.
Running the cte's individually I can see the data I'm looking for. Then I've started to add one cte at a time in the final cross join. I've noticed that for only one is "crashing" the results even though it's not throwing any error.
My final test, I've moved the problematic one as the first cte in my final select statement and everything is working fine (in the following query, imagine cte_e becomes the first one in the final select).
the query looks like this:
;with cte_a as
(
//select
),
cte_b as
(
//select
),
cte_c as
(
//select
),
cte_d as
(
//select
)
,
cte_e as
(
//select
)
select * from
cte_a,
cte_b,
cte_c,
cte_d,
cte_e
Questions:
Is there any constrain related to type of the data when using cross joins?
Is there any limit related to the number of CTEs in a query?
How can I proper identify what is the issue with this CTE in particular?
No - there's no constraint on the column types which may be cross joined
No (subject to all SQL Server maximums of course) - have a look here at all of the maxes. There's no mention of maximum number of common table expresssions.
Join the particular CTE to the remaining CTE's pairwise. Somewhere there's a join condition between CTE's which returns zero rows.
I've changed the way I'm returning the data, rather than cross join, one value per row and now it's working as expected. Thank you all for trying to help.

Using sum on two queries joined using UNION ALL

I am using Microsoft SQL Server 2014. I have two queries that I have joined using Union. Each query gives me a total but I need to be able to get a total of those two queries. Therefore, take the values given in these two queries and add them together to give me my final number. The two queries are:
select sum(acct.balance) as 'Balance'
from acct
where
acct.status <> 'closed'
Union all
select sum(term.balance) as 'Balance'
from term
where
term.status = 'active'
I have tried other suggestions posted on here but none have worked. My query should show me the balance of Acct.balance + term.balance.
In this case, your problem is easy that you have only two values, so you even could have directly added them, instead of union-ing them. I only give this example for completion and theory.
select (select sum(acct.balance) from acct where acct.status <> 'closed' ) + (select sum(term.balance) from term where term.status = 'active') as Balance
I mention that because it seems like the union all is what got you stuck. And yes, you can put that in a sub query or CTE, but in this case you don't even have a set, but just two values, since you aren't grouping by anything.
Other examples show CTE and subquery, which is how you can continue and build upon an existing query. (Another option may be to create a view if it's going to get reused a lot, but again, that is overkill for your example.)
When to use which?
I prefer CTE when I'm going to join something in more than once. For example, if I find and rank something, and then join the prior item to the next item. There are also other tricks with CTE's that go beyond that into areas like recursion. (http://www.databasejournal.com/features/mssql/article.php/3910386/Tips-for-Using-Common-Table-Expressions.htm)
If I just have a query that I want to build upon, I often just make it a subquery as long as the code is pretty short and straight forward.
A nice thing about either a CTE or a sub query is that you can select that inner code, and run just that when you're trying to understand why you're seeing the actual results.
All that being said, I don't generally like to see subqueries with the select region, so how I'd actually write this would be closer to :
select sum(SubTotals.Balance) as Balance
from
(
select sum(acct.balance) as Balance
from acct
where acct.status <> 'closed'
Union all
select sum(term.balance) as Balance
from term
where term.status = 'active'
) SubTotals
I give that example with the comment that meaningful names are good.
you can use CTE to do this
;with mycte as (
select
sum(acct.balance) as 'Balance'
from acct
where acct.status <> 'closed'
Union all
select sum(term.balance) as 'Balance'
from term
where
term.status = 'active'
)
Select
sum(Balance) as total_balance
from mycte
select sum(t.balance) from
(select balance
from acct
where
acct.status <> 'closed'
Union all
select balance
from term
where
term.status = 'active') t

SQL query inside a query

Allow me to share my query in an informal way (not following the proper syntax) as I'm a newbie - my apologies:
select * from table where
(
(category = Clothes)
OR
(category = games)
)
AND
(
(Payment Method = Cash) OR (Credit Card)
)
This is one part from my query. The other part is that from the output of the above, I don’t want to show the records meeting these criteria:
Category = Clothes
Branch = B3 OR B4 OR B5
Customer = Chris
VIP Level = 2 OR 3 OR 4 OR 5
SQL is not part of my job but I’m doing it to ease things for me. So you can consider me a newbie. I searched online, maybe I missed the solution.
Thank you,
HimaTech
There's a few ways of doing this (specifically within SQL - not looking at MDX here).
Probably the easiest to understand way would be to get the dataset that you want to exclude as a subquery, and use the not exists/not in command.
SELECT * FROM table
WHERE category IN ('clothes', 'games')
AND payment_method IN ('cash', 'credit card')
AND id NOT IN (
-- this is the subquery containing the results to exclude
SELECT id FROM table
WHERE category = 'clothes' [AND/OR]
branch IN ('B3', 'B4', 'B5') [AND/OR]
customer = 'Chris' [AND/OR]
vip_level IN (2, 3, 4, 5)
)
Another way you could do it is to do left join the results you want to exclude on to the overall results, and exclude these results using IS NULL like so:
SELECT t1.*
FROM table
LEFT JOIN
(SELECT id FROM table
WHERE customer = 'chris' AND ...) -- results to exclude
AS t2 ON table.id = t2.id
WHERE t2.id IS NULL
AND ... -- any other criteria
The trick here is that when doing a left join, if there is no result from the join then the value is null. But this is certainly more difficult to get your head around.
There will also be different performance impacts from doing it either way, so it may be worth looking into it. This is probably a good place to start:
What's the difference between NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULL?

SQL Server : group all data by one column

I need some help in writing a SQL Server stored procedure. All data group by Train_B_N.
my table data
Expected result :
expecting output
with CTE as
(
select Train_B_N, Duration,Date,Trainer,Train_code,Training_Program
from Train_M
group by Train_B_N
)
select
*
from Train_M as m
join CTE as c on c.Train_B_N = m.Train_B_N
whats wrong with my query?
The GROUP BY smashes the table together, so having columns that are not GROUPED combine would cause problems with the data.
select Train_B_N, Duration,Date,Trainer,Train_code,Training_Program
from Train_M
group by Train_B_N
By ANSI standard, the GROUP BY must include all columns that are in the SELECT statement which are not in an aggregate function. No exceptions.
WITH CTE AS (SELECT TRAIN_B_N, MAX(DATE) AS Last_Date
FROM TRAIN_M
GROUP BY TRAIN_B_N)
SELECT A.Train_B_N, Duration, Date,Trainer,Train_code,Training_Program
FROM TRAIN_M AS A
INNER JOIN CTE ON CTE.Train_B_N = A.Train_B_N
AND CTE.Last_Date = A.Date
This example would return the last training program, trainer, train_code used by that ID.
This is accomplished from MAX(DATE) aggregate function, which kept the greatest (latest) DATE in the table. And since the GROUP BY smashed the rows to their distinct groupings, the JOIN only returns a subset of the table's results.
Keep in mind that SQL will return #table_rows X #Matching_rows, and if your #Matching_rows cardinality is greater than one, you will get extra rows.
Look up GROUP BY - MSDN. I suggest you read everything outside the syntax examples initially and obsorb what the purpose of the clause is.
Also, next time, try googling your problem like this: 'GROUP BY, SQL' or insert the error code given by your IDE (SSMS or otherwise). You need to understand why things work...and SO is here to help, not be your google search engine. ;)
Hope you find this begins your interest in learning all about SQL. :D

Right way to use distinct in SQL Server

I am trying to retrieve some records based on the query
Select distinct
tblAssessmentEcosystemCredit.AssessmentEcosystemCreditID,
tblSpecies.CommonName
from
tblAssessmentEcosystemCredit
left join
tblSpeciesVegTypeLink on tblAssessmentEcosystemCredit.VegTypeID = tblSpeciesVegTypeLink.VegTypeID
left join
tblSpecies on tblSpecies.SpeciesID = tblSpeciesVegTypeLink.SpeciesID
where
tblAssessmentEcosystemCredit.SpeciesTGValue < 1
The above query returns 17,000 records but when I remove tblSpecies.CommonName, it retrieves only 4200 (that's actually correct).
I have no idea how to distinct only tblAssessmentEcosystemCredit.AssessmentEcosystemCreditID column and retrieve all other table columns in the query.
This query selects the different COMBINATION of AssessmentEcosystemCreditID and CommonName; if you want only one row per value of AssessmentEcosystemCreditID then you need to use a GROUP BY, as suggested by #JonasB; however, in that case, there could be several values of CommonName per value of AssessmentEcosystemCreditID , and so SQL requires you to specify WHICH one you want
Select tblAssessmentEcosystemCredit.AssessmentEcosystemCreditID ,
max(tblSpecies.CommonName) as CommonName,
min(tblSpecies.CommonName) as CommonName2, -- so you can verify you only have one value
from tblAssessmentEcosystemCredit
left join tblSpeciesVegTypeLink
on tblAssessmentEcosystemCredit.VegTypeID = tblSpeciesVegTypeLink.VegTypeID
left join tblSpecies on tblSpecies.SpeciesID= tblSpeciesVegTypeLink.SpeciesID
where tblAssessmentEcosystemCredit.SpeciesTGValue <1
GROUP BY tblAssessmentEcosystemCredit.AssessmentEcosystemCreditID
See this topic: mySQL select one column DISTINCT, with corresponding other columns
You probably have to deactivate ONLY_FULL_GROUP_BY, see http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by

Resources