Update table by calculating values from other table of last month - sql-server

In SQL-server database I want to update the table1 with the value of table2, I have two tables pay_tbl and bill_tbl. Those two have the following attributes.
pay_tbl
pay_ID type int -->pk
outstanding_amount type int
bill_tbl
pay_ID type int --> Fk
amount_to_Pay type int
amount_paid type int
paid_date type date
bill_status type varchar
I want to update the outstanding_amount column of pay_tbl by adding the value of amount_to_pay column of table2
(outstanding_payment+=amount_to_pay)
but just update those where bill status is 'Not Paid' and date is last month with respect to current month, i.e: now month is February then only update table where date is in Janurary. I tried following query but I know it is wrong
UPDATE pay_tbl
SET
outstanding_payment = outstanding_Payment +
(SELECT
amount_to_pay
FROM bill_tbl INNER JOIN bill_tbl ON
bill_tbl.pay_ID = pay_tbl.payID )
WHERE
MONTH(Date) = DATEPART(MONTH, DATEADD(MONTH, -1, [Date]))
AND YEAR(Date) = DATEPART(YEAR, DATEADD(MONTH, -1, [Date]))

UPDATE
TABLE_A
SET
TABLE_A.OUTSTANDING_PAYMENT = TABLE_A.OUTSTANDING_PAYMENT+TABLE_B.AMOUNT_TO_PAY
FROM
PAY_TBL AS TABLE_A
INNER JOIN (SELECT SUM(AMOUNT_TO_PAY) AMOUNT_TO_PAY ,PAY_ID FROM BILL_TBL WHERE MONTH(DATE) = DATEPART(MONTH, DATEADD(MONTH, -1, [DATE]))
AND YEAR(DATE) = DATEPART(YEAR, DATEADD(MONTH, -1, [DATE]))
AND BILL_STATUS='NO PAID'
GROUP BY PAY_ID) AS TABLE_B
ON TABLE_A.PAY_ID = TABLE_B.PAY_ID

Related

Adding the total number of distinct customers to a cte table in Microsoft SQL Server

I am using Microsoft SQL Server and am trying to achieve the following
Date
Distinct Customers last 30Days
2020-12-01
20000
2020-12-02
23000
What I am trying to get is that between 2020-11-01 and 2020-12-01 I had 20000 distinct customers.
I have created a cte table with the List of Dates as can be seen below:
WITH listdate AS
(
SELECT CAST('2020-11-01' AS datetime) DateValue
UNION ALL
SELECT DateValue + 1
FROM listdate
WHERE DateValue + 1 < getdate()
)
SELECT
cast(DateValue as date) as DateValue
FROM listdate d
Now I am trying to join the customer and usage table with the list of dates table, however, I am not getting the correct end result. The following is what I have tried doing:
WITH listdate AS
(
SELECT CAST('2020-11-01' AS datetime) DateValue
UNION ALL
SELECT DateValue + 1
FROM listdate
WHERE DateValue + 1 < getdate()
)
SELECT
cast(DateValue as date) as DateValue
,count(distinct case when m.CallDate between dateadd(dd,-30,cast(d.datevalue as date)) and cast(d.datevalue as date) then m.Customerid end) as Distinct_CID
FROM listdate d
join Usage m on d.DateValue=m.CallDate
left join Customer c on c.CustomerID=m.Customer
where c.customertype = 'type A'
group by d.DateValue
OPTION (MAXRECURSION 0)
Can someone maybe suggest a different way of how to solve such a query?
Thanks
I would go for a lateral join to bring the count of distinct customers for the last 30 days:
with listdate as (
select cast('20201101' as date) as datevalue
union all
select dateadd(day, 1, datevalue) from listdate where datevalue < cast(getdate() as date)
)
select ld.datevalue, x.cnt
from listdate ld
cross apply (
select count(distinct c.customerid) as cnt
from usage u
inner join customer c on c.customerid = u.customerid
where
c.customertype = 'type A'
and c.calldate >= dateadd(day, -29, datevalue)
and c.calldate < dateadd(day, 1, datevalue)
) x
option (maxrecursion 0)
Note that I simplified the parts related to dates: this uses proper literal dates and date arithmetics in the recursive query; the where clause of the subquery implements what I understand as the last 30 days (today + the preceding 29 days), and properly handles the time portion of calldate, if any.

How to SUM the Duration_Hours when it is LEFT JOIN of another database table?

I want to generate a report that summarizes the total working hours for every employee.
Below is my SQL query
SELECT WO_MaidName
,Maid_Name AS WO_selectMaidName
,Appointment_Duration
,Duration_Hours AS Appointment_selectDuration
FROM Appointments A
LEFT JOIN Maid
ON Maid_ID = WO_MaidName
LEFT JOIN Duration
ON Duration_ID = Appointment_Duration
WHERE DATEPART(m, Appointment_DateTime) = DATEPART(m, DATEADD(m, -1, getdate()))
AND DATEPART(yyyy, Appointment_DateTime) = DATEPART(yyyy, DATEADD(m, -1, getdate()))
AND (A.IsDelete = 0
OR A.IsDelete IS NULL
)
ORDER BY Appointment_ID DESC
The output is as follow which only display the working hours without adding these two value
How to SUM the Duration_Hours when it is LEFT JOIN of another database table so that the report will list the total working hours for every employee?
Edited:
I tried this query but giving me this:
'Column 'Maid.Maid_Name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.'
SELECT WO_MaidName
,Maid_Name AS WO_selectMaidName
,Appointment_Duration
,SUM(Duration_Hours) AS Appointment_selectDuration
FROM Appointments A
LEFT JOIN Maid
ON Maid_ID = WO_MaidName
LEFT JOIN Duration
ON Duration_ID = Appointment_Duration
WHERE DATEPART(m, Appointment_DateTime) = DATEPART(m, DATEADD(m, -1, getdate()))
AND DATEPART(yyyy, Appointment_DateTime) = DATEPART(yyyy, DATEADD(m, -1, getdate()))
AND (A.IsDelete = 0
OR A.IsDelete IS NULL
)
GROUP BY WO_MaidName
ORDER BY Appointment_ID DESC
How to solve this?
The error you are getting is telling you what to do:
'Column 'Maid.Maid_Name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.'
All columns in a select query that perform an aggregation neet to either be aggregated or in a group by. You need to add both Maid.Maid_Name and Appointment_Duration to your group by.

How to set date clause for prevous month in sql?

I want to get last values for prevous month (universal, not just for january :))
How can I set up where condition? Now it works well for current month, but i want result for prevous.
SELECT MAX(v.timestamp) AS Date,
MAX(v.value) AS Stanje,
v.tag_id, t.prik_sifr, t.tag_name
FROM dbo.tag_values AS v INNER JOIN
dbo.typ_tag AS t ON v.tag_id = t.id
WHERE (t.prik_sifr IS NOT NULL) AND (t.unit = 'M3') AND
(DATEPART(YEAR, v.timestamp) = DATEPART(YEAR, SYSDATETIME())) AND
(DATEPART(MONTH, v.timestamp)= DATEPART(MONTH, SYSDATETIME())) GROUP BY v.tag_id, t.prik_sifr, t.tag_name)
You need to subtruct one month from the current date:
SELECT MAX(v.timestamp) AS Date,
MAX(v.value) AS Stanje,
v.tag_id, t.prik_sifr, t.tag_name
FROM dbo.tag_values AS v INNER JOIN
dbo.typ_tag AS t ON v.tag_id = t.id
WHERE (t.prik_sifr IS NOT NULL) AND (t.unit = 'M3') AND
(DATEPART(YEAR, v.timestamp) = DATEPART(YEAR, DATEADD(MONTH, -1 SYSDATETIME()))) AND
(DATEPART(MONTH, v.timestamp)= DATEPART(MONTH, DATEADD(MONTH, -1 SYSDATETIME())))
GROUP BY v.tag_id, t.prik_sifr, t.tag_name)

tsql UNION without nulls

I have the following query
SELECT MONTH, COUNT(DISTINCT VISITS) AS BRAND_VISITS, NULL AS NONB_VISITS
FROM Table1
WHERE KEYWORD_TYPE = BRAND(
AND DATE >= '2013-01-01'
GROUP BY MONTH
UNION ALL
SELECT MONTH, NULL, COUNT(DISTINCT VISITS) AS NONB_VSTS
FROM Table1
WHERE KEYWORD_TYPE = NON-BRAND
AND DATE >= '2013-01-01'
GROUP BY MONTH
I get the following results:
1 352540 NULL
2 309834 NULL
3 228764 NULL
4 236054 NULL
5 218096 NULL
6 172527 NULL
1 NULL 5337
2 NULL 14120
3 NULL 9954
4 NULL 23755
5 NULL 19771
6 NULL 30797
However, what I want is inline results without NULLS
1 352540 5337
2 309834 14120
3 228764 9954
4 236054 23755
5 218096 19771
6 172527 30797
You can do this with using a single statement with CASE or with an JOIN on month instead of a UNION. If you take the join approach you may need to account for null values (no visist for a keyword in a month). You will want to profile them to see which is faster with your data and table structure. It is really all about the indexes and the amount of data you need to aggregate.
Assuming you don't have to worry about nulls based on the counts in your example, here is what you want.
SELECT brand.month, brand.brand_visits,nonbrand.non_brand_visits
FROM (SELECT month, COUNT(visits) AS brand_visits
FROM Table1
WHERE keyword_type = 'BRAND'
AND date >= '2013-01-01'
GROUP BY month) brand
INNER JOIN
(SELECT month, COUNT(visits) AS non_brand_visits
FROM Table1
WHERE keyword_type = 'NON-BRAND'
AND date >= '2013-01-01'
GROUP BY month) nonbrand
ON brand.month=nonbrand.month
Here is the CASE approach. You should profile based on your actual data you are aggregating and your indexes to see which method is faster.
SELECT month,
SUM(CASE WHEN keyword_type = 'BRAND' THEN 1 ELSE 0 END) AS brand_visits,
SUM(CASE WHEN keyword_type = 'NON-BRAND' THEN 1 ELSE 0 END) AS non_brand_visits
FROM Table1
WHERE date >= '2013-01-01'
GROUP BY month
Finally, you did not provide table structure or example data so I made some assumptions above. I strongly believe you did not need the COUNT(DISTINCT in your original statement. I have removed it and verified the two statement above yield the same results. If COUNT(DISTINCT is required then the CASE approach will not work but the join approach will still work fine.
Using your columns:
SELECT month,
count(distinct CASE WHEN keyword_type = 'BRAND' THEN visits END) AS BRAND_VISITS,
count(distinct CASE WHEN keyword_type = 'NON-BRAND' THEN visits END) AS NONB_VSTS
FROM Table1
WHERE date >= '2013-01-01'
and keyword_type in ('BRAND','NON-BRAND')
GROUP BY month
Am tempted to believe that month is simply the month from the date column, I would prefer this solution, it con cover more years than 1 and the same query will still be valid in the year 2014
SELECT cast(dateadd(month, datediff(month, 0, date), 0) as date) month,
count(distinct CASE WHEN keyword_type = 'BRAND' THEN visits END) AS BRAND_VISITS,
count(distinct CASE WHEN keyword_type = 'NON-BRAND' THEN visits END) AS NONB_VSTS
FROM Table1
WHERE date >= '2013-01-01'
and keyword_type in ('BRAND','NON-BRAND')
GROUP BY datediff(month, 0, date)
If you want to stick with your old script, you can fix it this way:
SELECT MONTH, max(BRAND_VISITS) BRAND_VISITS, max(NONB_VISITS) NONB_VISITS
FROM
(
SELECT MONTH, COUNT(DISTINCT VISITS) AS BRAND_VISITS, NULL AS NONB_VISITS
FROM Table1
WHERE KEYWORD_TYPE = 'BRAND'
AND DATE >= '2013-01-01'
GROUP BY MONTH
UNION ALL
SELECT MONTH, NULL, COUNT(DISTINCT VISITS) AS NONB_VSTS
FROM Table1
WHERE KEYWORD_TYPE = 'NON-BRAND'
AND DATE >= '2013-01-01'
GROUP BY MONTH
) a
GROUP BY MONTH

How to return values from SQL server database within intervals

Hi I have an SQL server database with 3 columns Activity[start_date(datetime),end_date(datetime),title(string)]
and I wish to count for a whole year, how many activities have start_date in each month, I mean I would like a return of 12 values(12 months) that count the activities within the months, thanks.
If there is an index on start_date and/or if you need to include months in the result even if there was no activity in that month, you might consider this one:
DECLARE #year INT;
SET #year = 2012;
;WITH n AS
(
SELECT TOP (12) m = DATEADD(MONTH, ROW_NUMBER() OVER
(ORDER BY name)-1, DATEADD(YEAR, #year-1900, 0))
FROM sys.all_objects ORDER BY name
)
SELECT [Month] = n.m, ActivityCount = COUNT(t.title)
FROM n
LEFT OUTER JOIN dbo.unspecified_table_name AS t
ON t.start_date >= n.m
AND t.start_date < DATEADD(MONTH, 1, n.m)
GROUP BY n.m
ORDER BY [Month];
(If you don't want a row when there were zero activities in a given month, then change LEFT OUTER to INNER.)
select month(start_date) as Month, count(*) as Count
from Activity
where year(start_date) = 2011
group by month(start_date)
order by month(start_date)

Resources