SQL Server 2012 Count - sql-server

I'm using SQL Server 2012. I have a table CustomerMaster. Here is some sample content:
+--------+---------------+-----------------+-------------+
| CustNo | NewMainCustNo | Longname | NoOfMembers |
+--------+---------------+-----------------+-------------+
| 3653 | 3653 | GroupId:003 | |
| 3654 | 3654 | GroupId:004 | |
| 11 | 3653 | Peter Evans | |
| 155 | 3653 | Harold Charley | |
| 156 | 3654 | David Arnold | |
| 160 | 3653 | Mickey Willson | |
| 2861 | 3653 | Jonathan Wickey | |
| 2871 | 3653 | William Jason | |
+--------+---------------+-----------------+-------------+
The NewMainCustNo for Customer records is equivalent to CustNo from Group records. Basically each customer belongs to a particular group.
My question is how to update the NoOfMembers column for group records with total number of customer belongs to a certain group.
Please share your ideas on how to do this.
Thank you...

This is the solution I came up with
update CustomerMaster
set NoOfMembers = (select count(*) from CustomerMaster m2 where m2.NewMainCustNo = CustomerMaster.CustNo and m2.CustNo <> CustomerMaster.CustNo)
where LongName like 'GroupId:%'
Check this SQL Fiddle to see the query in action.
However I disagree with your data structure. You should have a separate table for your groups. In your customer table you only need to reference the ID of the group in the group table. This makes everything (including the query above) much cleaner.

If I understand correctly, you can use a window function for the update. Here is an example with an updatable CTE:
with toupdate as (
select cm.*, count(*) over (partition by NewMainCustNo) as grpcount
from customermaster
)
update toupdate
set NoOfMembers = grpcount;

You may not have the option to do so, but I would separate groups out into their own table.
create table Groups (
GroupID int primary key,
Name varchar(200)
)
Then, change NewMainCustNo to GroupID, create, purge your customer table of groups, and go from there. Then, getting a group count would be:
select GroupID,
Name [Group Name],
COUNT(*)
from Groups g
join Customers c on
c.GroupID = g.GroupID

Related

Check if records exists at least once in LEFT JOINED Table

I have an Images, Orders and OrderItems table, I want to match for any images, if any has already been bought by the User passed as parameters by displaying true or false in an IsBought column.
Select Images.Id,
Images.Title,
Images.Description,
Images.Location,
Images.PriceIT,
Images.PostedAt,
CASE WHEN OrderItems.ImageId = Images.Id THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT) END
AS 'IsBought'
FROM Images
INNER JOIN Users as u on Images.UserId = u.Id
LEFT JOIN Orders on Orders.UserId = #userId
LEFT JOIN OrderItems on Orders.Id = OrderItems.OrderId and OrderItems.ImageId = Images.Id
Group By Images.Id,
Images.Title,
Images.Description,
Images.Location,
Images.PriceIT,
Images.PostedAt,
OrderItems.ImageId,
Orders.UserId
When I use this CASE WHEN I have duplicates when the item has been bought where IsBought is True and the duplicate is False.
In the case where the Item has never been bought, there is no duplicates, IsBought is just equal to False
----------------------------------
| User | type |
----------------------------------
| Id | nvarchar(450) |
----------------------------------
| .......|
----------------------------------
----------------------------------
| Orders | type |
----------------------------------
| Id | nvarchar(255) |
----------------------------------
| UserId | nvarchar(450) |
----------------------------------
| ........................... |
----------------------------------
----------------------------------
| OrderItems | type |
----------------------------------
| Id | nvarchar(255) |
----------------------------------
| OrderId | nvarchar(255) |
----------------------------------
| ImageId | int |
----------------------------------
----------------------------------
| Images | type |
----------------------------------
| Id | int |
----------------------------------
| UserId | nvarchar(450) |
----------------------------------
| Title | nvarchar(MAX) |
----------------------------------
| Description| nvarhar(MAX) |
----------------------------------
| ......................... |
----------------------------------
Any ideas on how I could just have one row per Images with IsBought set to true or false but not duplicates?
I would like something like this:
----------------------------------------------------------------------------
| Id | Title | Description | Location | PriceIT | Location | IsBought |
----------------------------------------------------------------------------
| 1 | Eiffel Tower | .... | ...... | 20.0 | Paris | true |
----------------------------------------------------------------------------
| 2 | Tore di Pisa | .... | ...... | 20.0 | Italia | false |
---------------------------------------------------------------------------
| etc ......
---------------------------------------------------------------------------
Your query logic looks suspicious. It is unusual to see a join that consists only of a comparison of a column from the unpreserved table to a parameter. I suspect that you don't need a join to users at all since you seem to be focused on things "bought" by a person and not things "created" (which is implied by the name "author") by that same person. And a group by clause with no aggregate is often a cover-up for a logically flawed query.
So start over. You want to see all images apparently. For each, you simply want to know if that image is associated with any order of a given person.
select img.*, -- you would, or course, only select the columns needed
(select count(*) from Sales.SalesOrderDetail as orddet
where orddet.ProductID = img.ProductID) as [Order Count],
(select count(*) from Sales.SalesOrderDetail as orddet
inner join Sales.SalesOrderHeader as ord
on orddet.SalesOrderID = ord.SalesOrderID
where orddet.ProductID = img.ProductID
and ord.CustomerID = 29620
) as [User Order Count],
case when exists(select * from Sales.SalesOrderDetail as orddet
inner join Sales.SalesOrderHeader as ord
on orddet.SalesOrderID = ord.SalesOrderID
where orddet.ProductID = img.ProductID
and ord.CustomerID = 29620) then 1 else 0 end as [Has Ordered]
from Production.ProductProductPhoto as img
where img.ProductID between 770 and 779
order by <something useful>;
Notice the aliases - it is much easier to read a long query when you use aliases that are shorter but still understandable (i.e., not single letters). I've included 3 different subqueries to help you understand correlation and how you can build your logic to achieve your goal and help debug any issues you find.
This is based on AdventureWorks sample database - which you should install and use as a learning tool (and to help facilitate discussions with others using a common data source). Note that I simply picked a random customer ID value - you would use your parameter. I filtered the query to a range of images to simplify debugging. Those are very simple but effective methods to help write and debug sql.

SQL Server - tricky query to update contact id using ROW_NUMBER to reference index value

A previous developer used an index rather than the actual contactID to reference which of the associated contacts are the primary contact. The index works well when the app gets the contacts and sets the primary contact in the list on the page, but try joining for a report! Not easy; so I want to update the main table with the actual contact ID to make for a simple join and to avoid this buggary.
In this particular case, I need to update tblInquiry with the claimantContactID and agentContactID. Those two fields I just created and defaulted to 0. However, the challenge is to use the claimantContactIndex and agentContactIndex values from tblInquiry, to get the respective nth row from tblContacts. The index is 0 based, so if the index value is 2, then get the ID of the 3rd contact, for example.
Also, claimantContactIndex and agentContactIndex can either be NULL or some number. If NULL, then assume the first contact (index 0).
I will also add that the contacts index cannot have an order by on it because the application relies upon the natural order when getting the contacts list (there is no order by in the stored procedure), and selects then the index accordingly.
DB Platform: SQL Server 2008 R2 Express Edition.
I have the following table structure:
tblInquiry
id | claimantID | agentID | claimantContactIndex | agentContactIndex | claimantContactID | agentContactID
--------------------------------
1 | 1001 | 2001 | 2 | 0 | 0 | 0
2 | 1002 | NULL | 0 | NULL | 0 | 0
tblClaimant
id | name | address | phone | email
--------------------------------
1001 | Widgets Inc. | 123 W. Main | 5550000 | widgets#here.com
1002 | Thingies LLC. | 456 W. Main | 5551111 | thingies#here.com
tblAgent
id | name | address | phone | email
--------------------------------
2001 | Simon Bros. | 789 W. Main | 5552222 | simon#here.com
tblContacts
id | claimantID | agentID | fn | ln | phone | email
--------------------------------
3001 | 1001 | NULL | John | Doe | 5553333 | john#here.com
3002 | 1001 | NULL | Fred | Flynn | 5554444 | fred#here.com
3003 | 1001 | NULL | Mike | Brown | 55555555 | mike#here.com
3004 | 1001 | NULL | Susan | Pierce | 5556666 | susan#here.com
3005 | NULL | 2001 | Jeff | Bridges | 5557777 | jeff#here.com
3006 | NULL | 2001 | Karry | Sinclair | 5558888 | Karry#here.com
3007 | NULL | 2001 | Steve | Green | 5559999 | steve#here.com
3008 | NULL | 2001 | Peter | White | 5550001 | peter#here.com
Update:
I have worked out the select part of this solution and I can now get the correct claimant contact info using ROW_NUMBER() and a JOIN. I will add more to get correct agent contact info. I also handled the case where an index is NULL. And ultimately I will work this out to update the inquiry table now that I have the right contactID.
SELECT
i.id inquiryID, i.claimantContactIndex, i.agentContactIndex, i.claimantContactID, i.agentContactID
,r.id contactID, r.claimantID, r.agentID
,r.*
FROM
(
SELECT ROW_NUMBER()
OVER (Partition by con.claimantid Order by (SELECT NULL)) AS RowNumber, *
FROM tblContacts con
) r
INNER JOIN
tblInquiry i on i.claimantid = r.claimantid and ((isnull(i.claimantContactIndex, 0) + 1 = r.RowNumber ))
WHERE
i.id in (1, 2, 3, 4, 5)
ORDER BY
i.id
This issue was resolved by doing the following:
As I posted above, using ROW_NUMBER() and (SELECT NULL()) along with an isnull to handle null values to get the correct contacts.
I selected the results into a temp table.
I then updated the inquiry table by joining it to the temp table.
dropped temp table
I had to do this in two passes, once for claimants, a second time for agents.
Thx #EricH for pointing me in the right direction.
You could do something like:
Using ideas from here:
https://msdn.microsoft.com/en-us/library/ms186734.aspx
SELECT
ROW_NUMBER() OVER (Order by Id) AS RowNumber,
claimantID, agentID, (etc...)
FROM
tblContacts
To get an index based resultset. I'd drop it into a temp table and select from that where RowNumber = Whatever index you want.

I would like to Pivot column data related to one entity into one row in SQL Server [duplicate]

This question already has an answer here:
Pivot without aggregate function in MSSQL 2008 R2
(1 answer)
Closed 8 years ago.
I am selecting data specific to certain clients out of multiple tables where data from one client spans multiple rows, however I would like duplicate entries to be combined onto one row. One basic example would be as follows
+------------+-------+-------------------------------+
| ClientCode | Name | Email |
+------------+-------+-------------------------------+
| CAL01 | Doug | itsjustdoug#internet.org |
| CAL01 | Doug | doug#email.com |
| MER03 | Jane | janehasemail#email.com |
| MER03 | Jane | janerocks#web.com |
| MER03 | Jane | janehatesspam#justforspam.net |
+------------+-------+-------------------------------+
The results I am looking for would be more like
+------------+-------+-------------------+-------------------+-----------------------+
| ClientCode | Name | Email1 | Email2 | Email3 |
+------------+-------+-------------------+-------------------+-----------------------+
| CAL01 | Doug | itsjustdoug#inte | doug#email.com | NULL |
| MER03 | Jane | janehasemail#ema | janerocks#web.com | janehatesspam#justfor |
+------------+-------+-------------------+-------------------+-----------------------+
Here is what I have tried.
Select * From
(Select
ClientCode
,Name
,Email
From dbo.Clients) T
PIVOT(Max (Email) for Email in (Email1, Email2, Email3)) T2
This does not seem to be the correct way to achieve what I want. Any suggestions would be appreciated. It is worth noting that the actual query is much more complicated and contains many joins and perhaps several different instances where I would use this sort of "pivoting?"
Thanks
Generate Row_number per clientcode in pivot source query
And concatenate Email text with the generated row_number which will create the pivot column list
SELECT *
FROM (SELECT ClientCode,
NAME,
Email,
'Email'+ CONVERT(VARCHAR(50), Row_number() OVER(partition BY ClientCode ORDER BY email)) Emails
FROM dbo.Clients) T
PIVOT(Max (Email)
FOR Emails IN( [Email1],
[Email2],
[Email3])) T2
SQLFIDDLE DEMO

how to update only 1 item in a duplicate field in sql 2005

have a duplicate fields and i need to update only one row how do i do this with sql 2005?
my database is as seen below:
+----------------+-------+-------------+------------------+---------------+
| Transaction_no | User | Check-In | Check-Out | barcode |
+----------------+-------+-------------+------------------+---------------+
| 01-2013 | User1 | --/--/-- | 12/28/2013 11:10 | APH009300L030 |
| 01-2013 | User1 | --/--/-- | 12/28/2013 11:10 | APH009300L030 |
| 01-2013 | User1 | --/--/-- | 12/28/2013 11:10 | APH009300L030 |
| 01-2013 | User1 | --/--/-- | 12/28/2013 11:10 | APH009300L030 |
+----------------+-------+-------------+------------------+---------------+
Try Like this
;WITH NumberedTbl AS
(
SELECT ROW_NUMBER() OVER (
PARTITION User,Check-In,Check-Out,barcode,Transaction_no
ORDER BY User,Check-In,Check-Out,barcode,Transaction_no
) AS RowNumber,
User,Check-In,Check-Out,barcode,Transaction_no
FROM tbl
)
UPDATE T
SET Check-In= GETDATE()
FROM NumberedTbl T
WHERE T.RowNumber = 1
SELECT * FROM tbl
Please see Demo here
Source
What you need in your table is a primary key column. You can just add an identity field. Then you'll be able to easily write queries like the one you need.
RAnking functions like row_number , rank , dense_rank wont work as all th field values are same and applying ORDER BY on any column after partitioninh will generate same rank for all rows.
Instead add another column habing unique values eg Identity column qfter which you can use this columm in ORDER By clause.

select unique rows based on single distinct column [duplicate]

This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 7 months ago.
I want to select rows that have a distinct email, see the example table below:
+----+---------+-------------------+-------------+
| id | title | email | commentname |
+----+---------+-------------------+-------------+
| 3 | test | rob#hotmail.com | rob |
| 4 | i agree | rob#hotmail.com | rob |
| 5 | its ok | rob#hotmail.com | rob |
| 6 | hey | rob#hotmail.com | rob |
| 7 | nice! | simon#hotmail.com | simon |
| 8 | yeah | john#hotmail.com | john |
+----+---------+-------------------+-------------+
The desired result would be:
+----+-------+-------------------+-------------+
| id | title | email | commentname |
+----+-------+-------------------+-------------+
| 3 | test | rob#hotmail.com | rob |
| 7 | nice! | simon#hotmail.com | simon |
| 8 | yeah | john#hotmail.com | john |
+----+-------+-------------------+-------------+
Where I don't care which id column value is returned.
What would be the required SQL?
Quick one in TSQL
SELECT a.*
FROM emails a
INNER JOIN
(SELECT email,
MIN(id) as id
FROM emails
GROUP BY email
) AS b
ON a.email = b.email
AND a.id = b.id;
I'm assuming you mean that you don't care which row is used to obtain the title, id, and commentname values (you have "rob" for all of the rows, but I don't know if that is actually something that would be enforced or not in your data model). If so, then you can use windowing functions to return the first row for a given email address:
select
id,
title,
email,
commentname
from
(
select
*,
row_number() over (partition by email order by id) as RowNbr
from YourTable
) source
where RowNbr = 1
If you are using MySql 5.7 or later, according to these links (MySql Official, SO QA), we can select one record per group by with out the need of any aggregate functions.
So the query can be simplified to this.
select * from comments_table group by commentname;
Try out the query in action here
Since you don't care which id to return I stick with MAX id for each email to simplify SQL query, give it a try
;WITH ue(id)
AS
(
SELECT MAX(id)
FROM table
GROUP BY email
)
SELECT * FROM table t
INNER JOIN ue ON ue.id = t.id
SELECT * FROM emails GROUP BY email;

Resources