Using Max with Date Values with or without the Nulls - sql-server

Now, after so many hours trying to figure this out, i really now need help.
I have a table which contains millions of records of about 50,000 customers. Each customer has at least 2000 transactions.
I want to have a table that holds the latest date each customer had either bought or sold something on the website.
I have tried
'FOR PURCHASES
Update tblmycustomers
set LastBoughtdate = (Select ISNULL(Max(trndate), '01-Jan-1900') from tbltransactions where Type = 'PURCHASES')
from tbltransactions.AccountRef = tblmycustomers.AccountNo
It works fine for records that have "PURCHASES" but for those who dont have PURCHASES, it saves another date which is wrong
I want it to return the default date ("01-Jan-1900") for every customer who doesn't have purchases and return the Maximum transaction date for those who has.
Please help me.

Try this:
UPDATE c
SET LastBoughtdate = ISNULL(Q.MaxBoughtDate, '1900-01-01')
FROM tblmycustomers c
LEFT JOIN
(SELECT AccountRef, MAX(trndate) AS MaxBoughtDate
FROM tblTransactions
WHERE Type = 'PURCHASES'
GROUP BY AccountRef) Q ON Q.AccountRef = AccountNo

I believe this would work. The driver table being "customers", you want to left join to the transactions...so you get all customer records even if there is no transactions. So...do something like this :)
Select cust.AccountNo
, isnull(max(trans.trndate), convert(date,'01/01/1900')) as LastBoughtDate
from tblmycustomers as cust
left join tbltransactions as trans on cust.AccountNo = trans.AccountRef
where type = 'PURCHASES'
group by cust.AccountNo

This updates based on a max transdate of an left outer joined subquery of the account number.
UPDATE
T
SET
T.LastBoughtdate=COALESCE(A.LastPurchaseDate,'01/01/1900')
FROM
tblmycustomers T
LEFT OUTER JOIN
(
SELECT
T2.AccountRef
LastPurchaseDate=MAX(trndate)
FROM
tbltransactions T2
WHERE
T2.Type='PURCHASES'
GROUP BY
T2.AccountRef
)AS A ON A.AccountRef=T.AccountNo

If your "LastBoughtdate" is DateTime. I think you need to convert the "01-01-1900'. Convert(Date, '01-01-1900', 101).

Related

Summing a total from multiple sales into a single column

I'm having issues with what I believe should be a simple problem in SQL Server 2017. I need to show the total sales price for a given sale. This is what I have written (note I deleted the totalprice sum formulae because it returned an error) :
USE [Antiques]
GO
DECLARE #TotalPrice INT
SELECT
Sales.SaleNo,
Sales.SalesDate,
Customers.FirstName,
Customers.LastName,
Products.Price,
#TotalPrice AS TotalPrice
FROM
Customers JOIN Sales ON Customers.CustomerID = Sales.CustomerID
JOIN SalesProducts ON Sales.SaleNo = SalesProducts.SaleNo
JOIN Products ON SalesProducts.ProductID = Products.ProductID
WHERE (Products.ProductID = SalesProducts.ProductID)
GO
This is the result:
Even if I remove the item price (which I have just put in temporarily and won't be in final code) there are still multiple lines per sale (1 for each item in the sale). Have I used the wrong joins? How can I get it looking like this:
Can anyone please tell me what I'm doing wrong? I've tried so many ways of using the Sum function and Group By and failing. (Note: this has to be a basic query and not a stored procedure unfortunately)
Actually you're not too far away. I'd move the grouping in a derived table and join that, to get the totalprice.
SELECT sales.saleno,
sales.salesdate,
customers.firstname,
customers.lastname,
x.totalprice
FROM sales
INNER JOIN customers
ON customers.customerid = sales.customerid
INNER JOIN (SELECT salesproducts.saleno,
sum(products.price) totalprice
FROM salesproducts
INNER JOIN products
ON products.productid = salesproducts.productid
GROUP BY salesproducts.saleno) x
ON x.saleno = sales.salesno;

How to display monetary value in PostgreSQL

My database query is below, but I still can't display a monetary value properly. Please help me.
SELECT SUM (orders.quantity * products.price) as total,
to_char((orders.quantity * products.price), '$99,999,999.99') AS money
FROM
orders
inner join products on products.id = orders.products_id
inner join customers on customers.id = orders.customers_id
WHERE order_date BETWEEN CURRENT_DATE - INTERVAL '30 days'
AND CURRENT_DATE + INTERVAL '1 days';
My problem is that I get this error:
ERROR: column "orders.quantity" must appear in the GROUP BY clause or be used in an aggregate function
You didn't really say what your problem was, but if you use the FM format modifier as in
SELECT to_char(12345.67, '$99,999,999.99FM');
to_char
------------
$12,345.67
(1 row)
the result might be more to your liking.
To make the query work without an error, add a GROUP BY clause at the end like
... GROUP BY money

Filling up a table in sql with data from another table only if it does not already exist

I am working on a problem in SQL Server that is mind boggling. What I am trying to accomplish is, I have a table temp2 (picture below) that houses data from a lot of inner joins which is then used for a SSRS report.
The problem I am trying to solve is, how can I fill in the missing titles for each employee even if they have not put any values in it for the dates provided?
Question is, is it possible to fill in the missing titles from ProjectName for each Employee? As seen in the SSRS report, each employee should have all of the ProjectName being returned from the data set which is reading the table temp2...
EDIT
So This is what I tried and even Though I have gotten all the projectnames into my temp2, this is ugly and inefficient. The ssrs will take too long to run because of unwanted data.
Select distinct Employee = Coalesce(a.Employee, #SelectEmployee), EmpId = Coalesce(a.EmpId, (Select PkId from AllRef Where Ness='All')), c.Day, Title=Coalesce((case when a.Title like '%-%'
then left(a.Title, charindex('-', a.Title))
else a.Title
end),''), p.ProjectName, Description =coalesce(a.Description,''), Val = Coalesce(a.Val,''), AbbrevJob = COALESCE(a.abbrevjob, ''),
week1Total=(select sum(val) as week1 from temp1 WHERE day >= Dateadd("d", -14, #WeekEnding) AND day <= Dateadd("d", -7, #WeekEnding)),
week2Total=(select sum(val) as week2 from temp1 WHERE day >= Dateadd("d", -7, #WeekEnding) AND day <= #WeekEnding )
from dbo.Calender as c
left outer join temp2 as a
on c.Day = a.Day
cross join ProjectName p
--on p.PkId = a.Abbrevjob-2
Where c.Day >= Dateadd("d",-13,#WeekEnding) and c.Day <= #WeekEnding
order by EmpId asc
The Cross Join did accomplish the task but the repetition is killing performance. Anyone knows how to deal with that?
The usual way to do that is to build a matrix of all employees and all projects, and then optionally query the hours. For example:
; with Employees as
(
select distinct EmployeeName
from TableWithEmployees
)
, Projects as
(
select distinct ProjectName
from TableWithProjects
)
select *
from Employees e
cross join
Projects p
left join
TableWithDetails d
on d.EmployeeName = e.EmployeeName
and d.ProjectName = p.ProjectName
The left join means that rows without details will not be filtered out.
Though I never done it before, solution that comes upon my mind is pretty simple...
The problem with that report is that you try to inner join data with the project name table. It's not actually the problem, it's the right approach that everyone uses when they need such type of report.
But when it comes to the problem you stated, then it is the problem...
The point of getting the whole list of project names is outer joining project name table. But in that case you still get only projects per employee and if there is any project name not filled by employee record, it will still appear on the list, but only once and not assigned to any employee. And that's not what you need.
So solution is to outer join employees and project names first, and then inner join your data table.
You can just pick DISTINCT empId values from your data table and FULL OUTER JOIN it on ProjectNames. Then LEFT OUTER JOIN results to data table, this time by empId = empId and PkId = AbbrevJob (if I got right the columns which hold project name id-s).
It should work, let me know please whether it does or not, good luck with that!

SQL: Summing columns with a similar column in common

I'm extremely new to SQL Sever and so I apologize if the question is worded strange. I am doing a homework assignment, and this is the question:
"A manager wants to know the email address, number or orders, and the total amount of purchases made by each customer. Create a summary query that returns these three items for each customer that has orders."
I have all of the data queried, the problem is when I pull data from each customer, it will show the quantity of items per order, and I need the items to be pooled together into one column. This is my query thus far (again, total noob, please excuse any poor syntax, etc.)
SELECT EmailAddress,
ItemPrice - DiscountAmount * Quantity AS TotalPurchaseAmount,
COUNT(*) AS OrderQty
FROM Customers
JOIN Orders ON Customers.CustomerID = Orders.CustomerID
JOIN OrderItems ON Orders.OrderID = OrderItems.OrderID
GROUP BY Orders.CustomerID,
OrderItems.ItemPrice, OrderItems.DiscountAmount,
OrderItems.Quantity,
Customers.EmailAddress;
The following is a small bit of the result set that I get:
Email Address OrderTotal OrderQty
allan.sherwood#yahoo.com 253.15 2
allan.sherwood#yahoo.com 839.30 2
allan.sherwood#yahoo.com 1208.16 2
barryz#gmail.com 303.79 4
christineb#solarone.com 479.60 2
david.goldstein#hotmail.com 299.00 2
david.goldstein#hotmail.com 489.30 1
david.goldstein#hotmail.com 479.60 1
So as you can see, I have several orders I need to smoosh together into one single row per e-mail, I have looked and looked for an answer but the only thing I can find is how to find duplicates and ignore them, not combine their data. Any help is extremely appreciate, thanks so much for taking the time to read this :) If my question doesn't make sense please let me know so I can clear up any bad wording I may have used!
Just do GROUP BY CustomerID, EmailAddress:
SELECT
c.EmailAddress,
SUM((i.ItemPrice - i.DiscountAmount) * Quantity) AS TotalPurchaseAmount,
COUNT(*) AS OrderQty
FROM Customers c
INNER JOIN Orders o
ON c.CustomerID = o.CustomerID
INNER JOIN OrderItems i
ON o.OrderID = i.OrderID
GROUP BY
c.CustomerID, c.EmailAddress
Additional note: Use aliases for your tables
You need to change your formula and remove columns that you dont want to group by from select query..
for example your query should be something like this
SELECT EmailAddress,
--do your aggregation here
blah AS TotalPurchaseAmount,
COUNT(*) AS OrderQty
FROM Customers
JOIN Orders ON Customers.CustomerID = Orders.CustomerID
JOIN OrderItems ON Orders.OrderID = OrderItems.OrderID
GROUP BY Orders.CustomerID,
Customers.EmailAddress;

MSSQL - Join tables and return user based on value in another table column

probably a badly worded question so apologies.
I have 3 tables that I want to join together.
I have created an SQLFiddle here
What I am wanting, is to compare the MAXLINEDISCOUNT from the linkloads table to the allowed discounts in the price_escalation_bands table.
so in the data, the maxlinediscount of 40 must match the next highest discount in the price_escalation_bands table where the customer_band is the same.
so I want the result to match row 1, where it is bronze and discount is 45. should my MAXLINEDISCOUNT be greater than 45, then go to the next highest which could be 50 in this case.
when it matches, return the fk_salesman_userid field and match this to the username in the users table.
Obviously, all this data is dynamic so needs to look at next highest...
Currently, it is returning as blank so dont think my syntax is quite correct.
my query is:
select price_authorized,load_number,maxlinediscount,customer_band,[price_escalation_bands].fk_salesman_userid,Users.firstname firstname,totalcost,period,creditlimit,currentbalance,customername,totalcubes,treatedcubes,normalcubes,pricingissue from #linkloads
left outer JOIN [price_escalation_bands] on [price_escalation_bands].band=#linkloads.customer_band
AND price_escalation_bands.discount = (
SELECT top 1 [price_escalation_bands].[discount]
FROM [price_escalation_bands]
WHERE [price_escalation_bands].band=#linkloads.customer_band
AND [price_escalation_bands].[discount]<=#linkloads.maxlinediscount
ORDER BY [price_escalation_bands].[discount]
)
left outer join Users
on Users.userid=[price_escalation_bands].fk_salesman_userid
Help, appreciated as always.
This lists all price_escalation_bands entries over the matching limit in linkloads:
select u.username
, peb.band
, peb.discount
, ll.maxlinediscount
from price_escalation_bands peb
join Users u
on peb.fk_salesman_userid = u.UserID
join linkloads ll
on ll.customer_band = peb.band
where ll.maxlinediscount < peb.discount
Your SQL Fiddle example with this query.

Resources