SQL Server aggregate function with sum - sql-server

I want to use an aggregate function in SQL Server to sum the number of seats:
The table is like that (it's all the same software just version changes)
OrderID | CustomerID | ProductID | Product Name | No of Seats
1 | 11 | 351-0212-4 | soft v601,Download | 3
2 | 11 | 361-0313-5 | soft v701,Upgrade | 2
3 | 12 | 341-1210-4 | soft v501,Download | 5
4 | 12 | 351-0212-5 | soft v601,Upgrade | 2
...
And I want a result like
Sum(no of seats)
8
So If a customer already bought the software but have upgraded keep number of seats for the customer.
e.g.:
Customer 11 bought 3 licences of our soft and then he bought two upgrades of a newer vesion so the sum for him should be 3 instead of 5.
Is that something possible to do in SQL ?
I hope I've been clear if not let me know.
Thanks in advance.

something like
select CustomerID, sum([No of Seats])
from <your table>
where [Product Name] not like '%upgrade%'
group by CustomerID
But in general - filter out those you don't want to see in the results and then sum. And if you want total number (not per customer):
select sum([No of Seats])
from <your table>
where [Product Name] not like '%upgrade%'

you should add boolean column, like 'isActive', then your select can be like this
select customerid, sum(numberOfSeats) from table
where isActive = 1
group by customerid

You have some normalization problems. The Product Name column is (presumably) redundant with the ProductID column, plus Product Name
apparently carries two logically distinct pieces of information: the name itself, and whether that product is an upgrade.
It would be better to split this into two tables, say Products and Orders. The Products table would have columns ProductID (primary key), Product_Name, and Is_Upgrade, and the Orders table would have columns OrderID (primary key), CustomerID (foreign key), ProductID (foreign key), and NumberOfSeats.
Given what you now have, however, and assuming that you want to avoid counting seats where the product name ends in 'Upgrade', you seem to want a query along these lines:
SELECT SUM("No of seats")
FROM Orders
WHERE CustomerID = 11 AND "Product Name" NOT LIKE '%Upgrade'

Related

SQL Consecutive Sequence Number gets messed up with ORDER BY

I am working on Windows Form Application and it accesses database in SQL Server 2014. I have EmployeeTable which I retrieve data from, and display all the records in DataGridView. In this table, I have a column SequenceID, which basically increments from 1 up to the number of records in this table, but this is not the same as AUTO INCREMENT in that SequenceID gets updated each time the table is modified, and keeps the numerical order no matter how many times new records get inserted or some records are deleted. For example, if the data looks like
SequenceID | Name
1 | John
2 | Mary
3 | Robert
and Mary is removed, then the resulting table needs to look like
SequenceID | Name
1 | John
2 | Robert
In order to achieve this, I used the best answer by zombat from Update SQL with consecutive numbering, and it was working great until I used ORDER BY expression.
This EmployeeTable also has DateAdded column, containing the date when the record was inserted. I need to display all records ordered by this DateAdded column, with the oldest record shown at the top and the newest at the bottom in addition to the correct SequenceID order. However, it gets messed up when a record is deleted, and a new one is inserted.
If I insert 3 records like,
SequenceID | Name | DateAdded
1 | John | 9/25/2017
2 | Mary | 9/26/2017
3 | Robert | 9/27/2017
and remove Mary, it becomes
SequenceID | Name | DateAdded
1 | John | 9/25/2017
2 | Robert | 9/27/2017
and this is good so far. However, if I add another record Tommy on, say, 9/28/2017, which should be added at the bottom because it is the newest, it results in something like,
SequenceID | Name | DateAdded
1 | John | 9/25/2017
3 | Robert | 9/27/2017
2 | Tommy | 9/28/2017
The ORDER BY is working fine, but it messes up the SequenceID, and I am not sure why this is happening. All I am doing is,
SELECT *
FROM EmployeeTable
ORDER BY DateAdded
I tried placing zombat's SQL command both before and after this SQL command, but neither worked. It seems to me like when I delete a row, the row has an invisible spot, and a new record is inserted in there.
Is there any way to fix this so I can order the records by DateAdded and still have the SequenceID working correctly?
If you need id for GUI (presentation only) you could use:
SELECT ROW_NUMBER() OVER(ORDER BY DateAdded) AS sequenceId, Name, DateAdded
FROM EmployeeTable
ORDER BY DateAdded;
EDIT:
I am trying to update the SequenceID, but it is not getting updated
You should not try to reorder your table every time. It doesn't make sense.

I'm trying to count how many times data repeats in a table in SQL

I have a database that stores customer information in 2 tables.
Table stores
(tbl.contacts)
| Companyname | CountryID
and the second table (tbl_geo_country)
| ID | Countrycode | Name |
Now I want to create a report that can show me how many customers are from what country. example output
| Country | QNT |
Norway 5
USA 3
Sweden 2
I dont know how many different countries it has stored so it also needs to check that.
Seems like a JOIN and GROUP BY to me:
SELECT country.Name, COUNT(contact.ID) as QNT
FROM tbl_geo_country country
INNER JOIN tbl.contacts contact ON country.ID = contact.CountryID
GROUP BY country.Name
ORDER BY COUNT(contact.ID)
Keep in mind that this would return only countries, that have at least one contact. If you also need countries that have no contacts, you need to change INNER JOIN to LEFT JOIN.

Case Sensitive join TSQL

I am at a bit of a standstill here. I have a simple left outer join to a table that is returning an ID.
My code is as
Select distinct TenantID
,Name
,Name2
,TenantNumber
,Cashname
From Tenants
LEFT OUTER JOIN tCash
on TenantNumber = CashNumber
and tMoney.CashName = Tenants.Name2
My result set is as follows:
**TenantID | Name | Name2 | TenantNo | CashName**
100 |MyShop | John's shop | 12345 |John's shop
999 |MyShop | John's Shop | 12345 |John's shop
My Issue: for all intents and purposes, "John's shop" IS different from "John's Shop" - I am correctly joining my money table on the TenantNo and then on Name2, but name 2 is different by Case.
Question:
Is there any way to differentiate a join based on case sensitivity? I would not want to use UPPER or LOWER due to the fact that it would ruin the case on reporting.
Thanks!
Adding Table information below, please assume all columns are trimmed of whitespace.
tMoney
CashNumnbr | CashName
102504 Bill's Place
102374 Tom's Shop
12345 John's Shop
12345 John's shop
Tenants
TenantID | Name | Name2 |TenantNumber
1 |MyShop | John's Shop | 12345
2 |MyShop | John's shop | 12345
3 |Shoppee | Bill's Place | 102504
4 | Shop2 | Toms Shop | 102374
Since I want to join to get the correct TenantID for an AR report, I would want to make sure I am always bringing in the correct tenant. If the case is different, is there anything I can write to differentiate a situation like John's Shop?
The problem is that in the second row of your results "John's Shop" shouldn't have matched "John's shop"?
You can use a case sensitive collation.
This is probably best achieved by altering the collation of the columns involved to allow index use but you can also do it at run time with an explicit COLLATE clause as below.
SELECT DISTINCT TenantID,
Name,
Name2,
TenantNumber,
Cashname
FROM Tenants
LEFT OUTER JOIN tCash
ON TenantNumber = CashNumber
AND tMoney.CashName = Tenants.Name2 COLLATE Latin1_General_100_CS_AS
The comments about joining on id instead of name are likely correct though and would negate the need to do this at all.
If COLLATE ends up being too slow due to a lack of indexing, you could also do something like the below, where each 30 below must match the length of each column to avoid an invalid comparison.
LEFT OUTER JOIN tCash ON
TenantNumber = CashNumber
AND CONVERT(VARBINARY(30),LTRIM(RTRIM(tMoney.CashName))) = CONVERT(VARBINARY(30),LTRIM(RTRIM(Tenants.Name2)))

SQL Query returns multiple rows of the same record when View includes one-to-many table

In MS-SQL, I have a View 'ListingResult' which contains rows from tables 'ListingCategoryXref' and 'Listing'. This is the View statement:
SELECT
dbo.Listing.ListingName,
dbo.Listing.ListingId,
dbo.ListingCategoryXref.CategoryId
FROM dbo.Listing INNER JOIN
dbo.ListingCategoryXref ON dbo.Listing.ListingId = dbo.ListingCategoryXref.ListingId
GROUP BY
dbo.Listing.ListingName,
dbo.Listing.ListingId,
dbo.ListingCategoryXref.CategoryId
Listings can have many rows in ListingCategoryXref, thus.
ListingResult (View)
Listing (table)
ListingId ListingName StateId
1 Toms bar 3
2 French place 5
ListingCategoryXref (table)
ListingId CategoryId
1 10
1 15
The query below returns a row per Listing per ListingCategoryXref.
SELECT TOP(26)
[ListingResult].[ListingId],
[ListingResult].[ListingName]
FROM [ListingResult]
WHERE [ListingResult].[StateId] = 3
So 'Tom's Bar' is returned twice as it has two categories. I figure I can either change the query above, or change the ListingResult View in SQL. I still need to return 26 results which I can't dictate if I use a wrapped select statement with ROW_NUMBER() OVER(PARTITION BY ListingId. (Is that true?) I'm using LLBLGen to access the DB so I'd prefer to change the view, if that is possible? Apologies for my newness to SQL being that obvious.
From the query above, the following result will be returned...
ListingName | ListingId | CategoryId
Toms bar | 1 | 10
Toms bar |1 | 15
If you only want Toms bar to be returned once, you'll need to remove the CategoryId column from the result set, and the group by clause, or add CategoryId to an agrgate function, and remove it from the group by clause i.e.
SELECT
dbo.Listing.ListingName,
dbo.Listing.ListingId,
COUNT(dbo.ListingCategoryXref.CategoryId) as Categories
FROM dbo.Listing
INNER JOIN dbo.ListingCategoryXref ON dbo.Listing.ListingId = dbo.ListingCategoryXref.ListingId
GROUP BY dbo.Listing.ListingName, dbo.Listing.ListingId
Which will return...
ListingName | ListingId | Categories
Toms bar | 1 | 2
Can you give an example of what you would like to see?

Detecting Correlated Columns in Data

Suppose I have the following data:
OrderNumber | CustomerName | CustomerAddress | CustomerCode
1 | Chris | 1234 Test Drive | 123
2 | Chris | 1234 Test Drive | 123
How can I detect that the columns "CustomerName", "CustomerAddress", and "CustomerCode" all correlate perfectly? I'm thinking that Sql Server data mining is probably the right tool for the job, but I don't have too much experience with that.
Thanks in advance.
UPDATE:
By "correlate", I mean in the statistics sense, that whenever column a is x, column b will be y. In the above data, The last three columns correlate with each other, and the first column does not.
The input of the operation would be the name of the table, and the output would be something like :
Column 1 | Column 2 | Certainty
CustomerName | CustomerAddress | 100%
CustomerAddress | CustomerCode | 100%
There is a 'functional dependency' test built in to the SQL Server Data Profiling component (which is an SSIS component that ships with SQL Server 2008). It is described pretty well on this blog post:
http://blogs.conchango.com/jamiethomson/archive/2008/03/03/ssis-data-profiling-task-part-7-functional-dependency.aspx
I have played a little bit with accessing the data profiler output via some (under-documented) .NET APIs and it seems doable. However, since my requirement dealt with distribution of column values, I ended up going with something much simpler based on the output of DBCC STATISTICS. I was quite impressed by what I saw of the profiler component and the output viewer.
What do you mean by correlate? Do you just want to see if they're equal? You can do that in T-SQL by joining the table to itself:
select distinct
case when a.OrderNumber < b.OrderNumber then a.OrderNumber
else b.OrderNumber
end as FirstOrderNumber,
case when a.OrderNumber < b.OrderNumber then b.OrderNumber
else a.OrderNumber
end as SecondOrderNumber
from
MyTable a
inner join MyTable b on
a.CustomerName = b.CustomerName
and a.CustomerAddress = b.CustomerAddress
and a.CustomerCode = b.CustomerCode
This would return you:
FirstOrderNumber | SecondOrderNumber
1 | 2
Correlation is defined on metric spaces, and your values are not metric.
This will give you percent of customers that don't have customerAddress uniquely defined by customerName:
SELECT AVG(perfect)
FROM (
SELECT
customerName,
CASE
WHEN COUNT(customerAddress) = COUNT(DISTINCT customerAddress)
THEN 0
ELSE 1
END AS perfect
FROM orders
GROUP BY
customerName
) q
Substitute other columns instead of customerAddress and customerName into this query to find discrepancies between them.

Resources