I have two tables with common Quote_No and I need to sum Qty in Quote_Items with Required by Date in Table Quotes - sql

I am trying to get the sum of "Qty" in a Table A called "Quote_Items" based on a "Required_by_Date" from Table B called Quotes. Both tables have a common "Quote_No" The required date is one month ago.
I have used the following but it produces a NULL, but I cannot see why
select sum(Qty)
from quotes.Quote_Items_Quantities
left outer join quotes.Quotes on (Quote_Required_by_Date = Qty)
WHERE (DatePart(yy, Quote_Required_by_Date) = DatePart(yy, DateAdd(m,1,getdate()))) and
datepart(m,Quote_Required_by_Date) = datepart(m,dateadd(m,1,getdate()))
Any suggestions what I am doing wrong here.

Try this:
SELECT SUM(i.Qty)
FROM Quote_Items i
JOIN Quotes q on i.Quote_No = q.Quote_No
AND CONVERT(varchar, q.Required_by_Date, 112) = CONVERT(varchar, DATEADD(month, -1, getdate()), 112)
or this (equivalent without using JOIN)
SELECT SUM(i.Qty)
FROM Quote_Items i
WHERE EXISTS(SELECT 1 FROM Quotes WHERE Quote_No = i.Quote_No AND CONVERT(varchar, Required_by_Date, 112) = CONVERT(varchar, DATEADD(month, -1, getdate()), 112))

Your query is producing NULL because of the join condition. You have
on Quote_Required_by_Date = Qty
However, the date is not going to match the quantity. Instead, you need to match on the Quote_No, according to your question:
select sum(Qty)
from quotes.Quote_Items_Quantities qiq left outer join
quotes.Quotes q
on q.Quote_Required_by_Date = qiq.Qty
WHERE (DatePart(yy, Quote_Required_by_Date) = DatePart(yy, DateAdd(m,1,getdate()))) and
datepart(m,Quote_Required_by_Date) = datepart(m,dateadd(m,1,getdate()));
You can also simplify your query by using the month() and year() functions:
select sum(Qty)
from quotes.Quote_Items_Quantities qiq left outer join
quotes.Quotes q
on q.Quote_Required_by_Date = qiq.Qty
WHERE year(Quote_Required_by_Date) = year(DateAdd(m, 1, getdate()) and
month(Quote_Required_by_Date) = month(dateadd(m,1,getdate());
Finally, you mind find it useful to use group by and get the results for many months:
select year(Quote_Required_by_Date), month(Quote_Required_by_Date), sum(Qty)
from quotes.Quote_Items_Quantities qiq left outer join
quotes.Quotes q
on q.Quote_Required_by_Date = qiq.Qty
group by year(Quote_Required_by_Date), month(Quote_Required_by_Date)
order by 1 desc, 2 desc;

Related

SQL select distinct from a concatenated column

This query almost does what I want
SELECT staging.dbo.ITEM_CODES.ITEM_CODE, MAX(dbo.OC_VDAT_AUX.UDL40) AS SAMPLEDATE,
CONCAT(RTRIM(dbo.OC_VDATA.UDL1), RTRIM(dbo.OC_VDATA.UDL6)) as LinkID
FROM dbo.OC_VDATA
INNER JOIN dbo.OC_VDAT_AUX ON dbo.OC_VDATA.PARTNO = dbo.OC_VDAT_AUX.PARTNOAUX AND dbo.OC_VDATA.DATETIME = dbo.OC_VDAT_AUX.DATETIMEAUX
INNER JOIN stagingPLM.dbo.ITEM_CODES ON LEFT(dbo.OC_VDATA.PARTNO, 12) = staging.dbo.ITEM_CODES.SPEC_NO
AND LEFT(dbo.OC_VDAT_AUX.PARTNOAUX, 12) = stagingPLM.dbo.ITEM_CODES.SPEC_NO
INNER JOIN stagingPLM.dbo.PLANTS ON dbo.OC_VDATA.UDL1 = staging.dbo.PLANTS.PLANT_CODE
WHERE (CONVERT(DATETIME, dbo.OC_VDAT_AUX.UDL40) > DATEADD(day, - 30, GETDATE()))
GROUP BY CONCAT(RTRIM(dbo.OC_VDATA.UDL1), RTRIM(dbo.OC_VDATA.UDL6)),staging.dbo.ITEM_CODES.ITEM_CODE
Sample Table generated by query:
The end result that I am trying to achieve is the latest ITEM_CODE per unique LinkID Note the first and last rows in the table. The last row should not be pulled by the query.
How do I modify this query to make that happen?
I have tried various placements for DISTINCT and sub queries in the select and where statements.
I would do in your case with ROW_NUMBER window function and CTE.
Solution can be like this:
WITH FilterCTE AS
(
SELECT staging.dbo.ITEM_CODES.ITEM_CODE, MAX(dbo.OC_VDAT_AUX.UDL40) AS SAMPLEDATE,
CONCAT(RTRIM(dbo.OC_VDATA.UDL1), RTRIM(dbo.OC_VDATA.UDL6)) AS LinkID,
ROW_NUMBER() OVER (PARTITION BY CONCAT(RTRIM(dbo.OC_VDATA.UDL1), RTRIM(dbo.OC_VDATA.UDL6)) ORDER BY MAX(dbo.OC_VDAT_AUX.UDL40)) AS RowNumber
FROM dbo.OC_VDATA
INNER JOIN dbo.OC_VDAT_AUX ON dbo.OC_VDATA.PARTNO = dbo.OC_VDAT_AUX.PARTNOAUX AND dbo.OC_VDATA.DATETIME = dbo.OC_VDAT_AUX.DATETIMEAUX
INNER JOIN stagingPLM.dbo.ITEM_CODES ON LEFT(dbo.OC_VDATA.PARTNO, 12) = staging.dbo.ITEM_CODES.SPEC_NO
AND LEFT(dbo.OC_VDAT_AUX.PARTNOAUX, 12) = stagingPLM.dbo.ITEM_CODES.SPEC_NO
INNER JOIN stagingPLM.dbo.PLANTS ON dbo.OC_VDATA.UDL1 = staging.dbo.PLANTS.PLANT_CODE
WHERE (CONVERT(DATETIME, dbo.OC_VDAT_AUX.UDL40) > DATEADD(day, - 30, GETDATE()))
GROUP BY CONCAT(RTRIM(dbo.OC_VDATA.UDL1), RTRIM(dbo.OC_VDATA.UDL6)),staging.dbo.ITEM_CODES.ITEM_CODE
)
SELECT *
FROM FilterCTE
WHERE RowNumber = 1

SQL with as expression shows multiple results

I am writing a SQL query using with as expression. I always get a result in the square of what I required.
This is my query:
DECLARE #MAX_DATE AS INT
SET #MAX_DATE = (SELECT DATEPART(MONTH,FECHA) FROM ALBVENTACAB WHERE NUMALBARAN IN (SELECT DISTINCT MAX(NUMALBARAN) FROM ALBVENTACAB));
;WITH TABLE_LAST AS (
SELECT CONCAT(DATEPART(MONTH,FECHA),'-',DATEPART(YEAR,FECHA)) as LAST_YEAR_MONTH
,SUM(TOTALNETO) AS LAST_YEAR_VALUE
FROM ALBVENTACAB
WHERE DATEPART(YEAR,CURRENT_TIMESTAMP) -1 = DATEPART(YEAR,FECHA) AND NUMSERIE LIKE 'A%'
AND DATEPART(MONTH,FECHA) <= #MAX_DATE
GROUP BY CONCAT(DATEPART(MONTH,FECHA),'-',DATEPART(YEAR,FECHA))
)
,TABLE_CURRENT AS(
SELECT CONCAT(DATEPART(MONTH,FECHA),'-',DATEPART(YEAR,FECHA)) as CURR_YEAR_MONTH
,SUM(TOTALNETO) AS CURR_YEAR_VALUE
FROM ALBVENTACAB
WHERE DATEPART(YEAR,CURRENT_TIMESTAMP) <= DATEPART(YEAR,FECHA) AND NUMSERIE LIKE 'A%'
GROUP BY CONCAT(DATEPART(MONTH,FECHA),'-',DATEPART(YEAR,FECHA))
)
SELECT *
FROM TABLE_CURRENT, TABLE_LAST
When I run the query I get exactly the square of the result.
I want to compare sale monthly with last year.
2-2020 814053.3 2-2019 840295.1
1-2020 1094993.65 2-2019 840295.1
3-2020 293927.3 2-2019 840295.1
2-2020 814053.3 1-2019 1050701.68
1-2020 1094993.65 1-2019 1050701.68
3-2020 293927.3 1-2019 1050701.68
2-2020 814053.3 3-2019 887776.1
1-2020 1094993.65 3-2019 887776.1
3-2020 293927.3 3-2019 887776.1
I should get only 3 rows instead of 9 rows.
You need to properly join your two CTE - the way you're doing it now, you're getting a Cartesian product of each row in either CTE together.
Do something like:
*;WITH TABLE_LAST AS
( ....
),
TABLE_CURRENT AS
( ....
)
SELECT *
FROM TABLE_CURRENT curr
INNER JOIN TABLE_LAST last ON (some join condition here)
What that join condition is going to be - I have no idea, and cannot tell from your question - but you have to define how these two sets of data "connect" ....
It could be something like:
SELECT *
FROM TABLE_CURRENT curr
INNER JOIN TABLE_LAST last ON curr.CURR_YEAR_MONTH = last.LAST_YEAR_MONT
or whatever else makes sense in your situation - but basically, you need to somehow "tie together" these two sets of data and get only those rows that make sense - not just every row from "last" combined with every row from "curr" ....
While you already got the answer on how to join the two results, I thought I'd tell you how to typically approach such problems.
From the same table, you want two sums on different conditions (different years that is). You solve this with conditional aggregation, which does just that: aggregate (sum) based on a condition (year).
select
datepart(month, fecha) as month,
sum(case when datepart(year, fecha) = datepart(year, getdate()) then totalneto end) as this_year,
sum(case when datepart(year, fecha) = datepart(year, getdate()) -1 then totalneto end) as last_year
from albventacab
where numserie like 'A%'
and fecha > dateadd(year, -2, getdate())
group by datepart(month, fecha)
order by datepart(month, fecha);

a query displaying 0 instead of not showing

the following query is displaying the result i want except i want it to show 0 for each month with non production.
SELECT
DATENAME(MONTH, DATEADD(M, MONTH(PolicyDetails.IssuedDate), - 1)) AS Month,
SUM(PolicyDetails.Premium) AS TotalProduction,
DATENAME(YEAR, PolicyDetails.IssuedDate) AS Year
FROM PolicyDetails INNER JOIN Clients
ON PolicyDetails.ClientId = Clients.ClientId
WHERE (Clients.Username = #Username)
GROUP BY MONTH(PolicyDetails.IssuedDate), DATENAME(YEAR, PolicyDetails.IssuedDate)
Month Total Production -$$
2019 - August 30.00
2019 - October 45.00
in this table i want to show "2019 - September" with Total Production = 0 instead of displaying nothing. How ??
If you want to show all months in the data, probably the simplest method is to use conditional aggregation. Your calculation of the month seems awkward. You seem to want the previous month, so:
SELECT DATENAME(YEAR, pd.IssuedDate) AS Year,
DATENAME(MONTH, DATEADD(MONTH, -1, pd.IssuedDate)) AS Month,
SUM(CASE WHEN c.Username = #Username THEN pd.Premium ELSE 0 END) AS TotalProduction
FROM PolicyDetails pd INNER JOIN
Clients c
ON pd.ClientId = c.ClientId
GROUP BY DATENAME(YEAR, pd.IssuedDate), DATENAME(MONTH, DATEADD(MONTH, -1, pd.IssuedDate))
ORDER BY MIN(pd.IssuedDate)
This assumes that you have at least one row per month in the data.
Otherwise, the canonical approach is to generate the months you want (using a derived table or recursive CTE or calendar table). Your month arithmetic is a bit awkward for that solution. It would look like:
SELECT YEAR(DATEADD(MONTH, -1, months.mstart)),
MONTH(DATEADD(MONTH, -1, months.mstart)),
COALESCE(SUM(pd.Premium), 0) AS TotalProduction
FROM (VALUES (CONVERT(DATE, '2019-08-01')),
(CONVERT(DATE, '2019-09-01')),
(CONVERT(DATE, '2019-10-01'))
) months(mstart) LEFT JOIN
PolicyDetails pd
ON pd.IssuedDate >= DATEADD(month, -1, months.mstart) AND
pd.IssuedDate < months.mstart LEFT JOIN
Clients c
ON pd.ClientId = c.ClientId AND
c.Username = #Username
GROUP BY YEAR(DATEADD(MONTH, -1, months.mstart)),
MONTH(DATEADD(MONTH, -1, months.mstart))
ORDER BY MIN(pd.IssuedDate)
I suppose that might be a usecase for SQL-IF.
Syntax as follows:
SELECT IF([condition], "YES", "NO");
In your case, try to combine that with your query.
Maybe like this:
SELECT IF([subquery > 0] AS X, X, 0);
If-Condition Like:
SELECT IF((SELECT COUNT(*) FROM PolicyDetails ) > 0, 1, 0);
But you will have to combine that output with your existing query posted above, to gain the output if the table is filled.

Left Join without duplicate values from the left table when multiple values in right table

The Following query brings back a list of IDs and a list of times. It's bringing back multimple from the Left table because it appears multiple in the right table.
It Currently brings back this:
I want it to bring back the minimum value from the right table for each ID in the left table.
Any help appreciated!
set language british
SELECT dbo.Employee.EmployeeID, SUBSTRING(CONVERT(varchar, ClockTemp.ClockTime, 108), 1, 5) as ClockTime
FROM dbo.Employee LEFT JOIN
(
Select [ClockID]
,[EmployeeID]
,[ClockTypeID]
,[ClockDate]
,[ClockTime]
FROM dbo.Clock
WHERE dbo.Clock.ClockDate = DATEADD(DD, 0, CAST('07-11-2016' AS DATE)) AND Clock.ClockTypeID=1
) As ClockTemp
ON dbo.Employee.EmployeeID = ClockTemp.EmployeeID
ORDER BY dbo.Employee.EmployeeID,clocktemp.ClockTime
Maybe this query would work for you. You do not need to order by Clocktime as the minimum value will be brought through from the MIN aggregate.
I would also change the Clocktime field to TIME if you are using SQL 2008 so that you can avoid the substring convert.
set language british
SELECT dbo.Employee.EmployeeID, SUBSTRING(CONVERT(varchar, MIN(ClockTemp.ClockTime), 108), 1, 5) as ClockTime
FROM dbo.Employee LEFT JOIN
(
Select [ClockID]
,[EmployeeID]
,[ClockTypeID]
,[ClockDate]
,[ClockTime]
FROM dbo.Clock
WHERE dbo.Clock.ClockDate = DATEADD(DD, 0, CAST('07-11-2016' AS DATE)) AND Clock.ClockTypeID=1
) As ClockTemp
ON dbo.Employee.EmployeeID = ClockTemp.EmployeeID
GROUP BY dbo.Employee.EmployeeID
ORDER BY dbo.Employee.EmployeeID
Try that:
WITH minClockTimeCTE AS (
SELECT EmployeeID, min(ClockTime) as ClockTime
FROM ClockTemp
GROUP BY EmployeeID
)
SELECT Employee.EmployeeID, minClockTimeCTE.ClockTime
FROM Employee
LEFT OUTER JOIN minClockTimeCTE
ON Employee.EmployeeID = minClockTimeCTE.EmployeeID
You could change the left join to an outer apply top 1:
SELECT dbo.Employee.EmployeeID,
SUBSTRING(CONVERT(varchar, ClockTemp.ClockTime, 108), 1, 5) as ClockTime
FROM dbo.Employee
OUTER APPLY
(
SELECT TOP 1 [ClockID]
,[EmployeeID]
,[ClockTypeID]
,[ClockDate]
,[ClockTime]
FROM dbo.Clock
WHERE dbo.Clock.ClockDate = DATEADD(DD, 0, CAST('07-11-2016' AS DATE))
AND Clock.ClockTypeID=1
AND dbo.Employee.EmployeeID = ClockTemp.EmployeeID
ORDER BY ClockTime
) As ClockTemp
ORDER BY dbo.Employee.EmployeeID,clocktemp.ClockTime

Join data from hourly and 30 minute tables

I have a table with data every hour:
and a table with data every 30 minutes:
I would like to join these two tables (by date) to get batVolt and TA in the same table and repeat the values for batVolt for the 30 minutes between the hour.
SELECT *
FROM HourTable t
INNER JOIN HalfHourTable ht
ON CAST(t.repDate AS Date) = CAST(ht.repDate AS Date)
AND DATEPART(HOUR, t.repDate) = DATEPART(HOUR, ht.repDate)
Edit
Your query should be
SELECT n.repDate
, n.TA
, a.batVolt
FROM [DAP].[dbo].[ARRMet] AS n
FULL JOIN [DAP].[dbo].[array3] AS a
ON DATEPART(HOUR, n.repDate) = DATEPART(HOUR, a.repDate)
AND CAST(n.repDate AS DATE) = CAST(a.repDate AS DATE)
WHERE CAST(n.repDate AS DATE) = '20150831'
ORDER BY n.repDate DESC
I would do this slightly differently than M.Ali. This uses fewer functions and seems a bit simpler to me.
SELECT *
FROM HourTable t
INNER JOIN HalfHourTable ht on
t.repDate = dateadd(hour, datediff(hour, 0, ht.repDate), 0)
You could use DATEPART()
select ta.repDate, ta.code, ta.TA, bat.batVolt
from table2 ta
join table 1 bat
on (DATEPART(yyyymmddhh,bat.repDate) = DATEPART(yyyymmddhh, ta.repDate)
I don't remember exact syntax for datepart but should be something similar to this
You can try following
SELECT x.*, y.*
FROM BatVoltDetails x
INNER JOIN TADetails y
ON LEFT(CONVERT(VARCHAR, x.repDate, 120), 13) = LEFT(CONVERT(VARCHAR, y.repDate, 120), 13)