SQL SERVER query, Mutual Rows in Given ID - sql-server

I have a sql server query question. I have a table like below. Giving a parameter to stored procedure, I need to query mutual CustomFields in lists that I want. For example, if ListID is given 1 and 2 and 3, result table will have columns that gives me 'FullName' in that case, because only 'FullName' is in all three ID's. I did that which solved the issue somehow, but looking for a better and precise practice. Thanks
SELECT DISTINCT(CustomField)
FROM CustomFields a
WHERE EXISTS (
SELECT count(*)
FROM CustomFields b
WHERE a.CustomField = b.CustomField
HAVING count(*)>2
)
ORDER BY a.CustomField
CustomField ListID
PhoneNumber 1
Unvan 1
FullName 2
Surname 2
Regiob 2
FullName 3
BirthPlace 3
FullName 1

Here's a more common approach to find CustomFields that are in groups 1, 2 and 3:
SELECT CustomField
FROM CustomFields
WHERE ListID in (1,2,3)
GROUP BY
CustomField
HAVING COUNT(DISTINCT ListId) = 3
No subquery required, and the where clause filters out uninteresting groups before the group by.

I was thinking of something more along these lines, which is adapted from #Andomar and is a little more general.
CREATE TYPE ListIdType AS TABLE (
ListId int PRIMARY KEY
);
GO
CREATE PROCEDURE S
#ListIdTable ListIdType READONLY
AS BEGIN SET NOCOUNT ON;
SELECT CustomField
FROM CustomFields
WHERE ListID in (SELECT ListId FROM #ListIdTable)
GROUP BY
CustomField
HAVING COUNT(DISTINCT ListId) = (SELECT COUNT(ListId) FROM #ListIdTable)
END;

Related

Show accounts with multiple contacts to as separate columns rather than rows?

Suppose, I have a table of contacts.
That table has contact IDs and Account IDs
So if I do
Select ContactID,AccountID From table
I get this:
Instead, I want to see this:
Is this plausible?
With two and only two contacts par account, aggregation seems like a straight-forward option:
select account_id, min(contactId) contactId1, max(contactId) contactId2
from mytable
group by account_id
If some accounts have 2 contacts and others have just 1, then:
select
account_id,
min(contactId) contactId1,
case when count(*) > 1 then max(contactId) end contactId2
from mytable
group by account_id

How can I SELECT data that is exclusive?

I'm trying to write a SELECT statement that will pull data that only exists once. I have two columns, ItemID and OfficeID, and I need to find items from the ItemID column that are only registered to one office. Items can have multiple rows, one for each office they are assigned to. So a single ItemID can have multiple rows if it is used in multiple offices. Can I use a select statement with COUNT, or is there a better way?
Can't think of a place to start, but I've used COUNT in varying ways.
Using HAVING and EXISTS you can use the below query since Items can have multiple rows, one for each office they are assigned to which I read as an ItemID will only have multiple rows if it has multiple OfficeID. If there can be multiple rows for the same OfficeID just let us know.
select *
from table
where exists(select ItemID from table group by ItemID having count(*) = 1)
You must group by ItemID and in the having clause apply the condition count(*) = 1:
select ItemID
from tablename
group by ItemID
having count(*) = 1
or with NOT EXISTS:
select t.ItemID
from tablename t
where not exists (
select 1 from tablename
where ItemID = t.ItemID and OfficeID <> t.OfficeID
)
this will return all items for which there is not another row with the same ItemID but different OfficeID.

SQL Server getting newest entry returns wrong results. What am I missing?

I have a strange behaviour with a SQL Server query/function.
I have a table with 3 columns (actually there are more columns, but these 3 are relevant for this task). The columns are FileId, UserId and TimeCreated. It is possible, that one user can create the same FileId multiple times, and I want to know, which was the newest created file.
I am doing it with this WHERE clause:
WHERE TimeCreated IN (SELECT MAX(TimeCreated)
FROM table
GROUP BY FileId, UserId)
In my opinion this should be correct, but for some groups, it returns multiple rows, even if the TimeCreated is different.
Here is one result as an example:
TimeCreated | UserId | FileId
------------------------------------------------------
2016-01-18 00:00:00.000 | UserA | FileA
2016-01-18 06:00:00:000 | UserA | FileA
But it should only return the row with '2016-01-18 06:00:00:000' as TimeCreated value.
I don't understand what is going wrong, because there are a lot more entries, which have UserA (as UserId) AND FileA (as FileId) but different TimeCreated values but it only returns this two rows (so in some way, it is quite working) and like I said, for some groups it is ok, but sometimes it returns two rows with the same UserId and FileId but different TimeCreated values. And when this happens it's always two rows and not more.
The TimeCreated is a DateTimeOffset(7), UserId is a string as well as FileId. Maybe this is important to know...
Does someone have an explanation why this is happening?
You should use this syntax instead:
;WITH CTE as
(
SELECT
*,
row_number() over (partition by FileId, UserId ORDER BY TimeCreated DESC)rn
FROM <table>
)
SELECT * FROM CTE
WHERE rn = 1
What's going wrong is that your inner select returns more than one value. It returns the maximum of TimeCreated for each combination FileId and UserID in the table.
One way to solve it is this:
...
FROM table t1
INNER JOIN
(
select FileId, UserId, max(TimeCreated) as maxTimeCreated
from table
group by FileId, UserId)
)
t2 ON t1.TimeCreated = t2.maxTimeCreatedAND t1.UserId = t2.USerId AND T1.FileId = t2.FileId
However, if you post your table structure and desired results, someone might show you a better way.
You are not joining the subquery by UserId, so your lower TimeCreated may correspond to another user file.
from table t1
where TimeCreated = (select max(TimeCreated)
from table
where table.UserId = t1.UserId
and table.FileId = t1.FileId )

how to retrieve data from multiple table into a single table

I am having 3 tables Book Master, Category Master, Subcategory Master. In my Book Master table, column CategoryName have value from Category Master's ID column. And SubcategoryName column in Book Master have ID columns value from Subcategory Master.
Table structure of the 3 tables:
Book Master
Oid uniqueidentifier,
BookName nvarchar(100),
CategoryName uniqueidentifier,
SubCategoryName uniqueidentifier
Category Master
Oid uniqueidentifier,
CategoryName nvarchar(100)
Subcategory Master
Oid uniqueidentifier,
CategoryName uniqueidentifier,
SubCategoryName nvarchar(100)
I am working on one windows application,in that I have to show top 5 books from each category of book.Now I am having 10 records in table and I have used the following query to display the books on form.
select BM.BookName ,BM.BookImage,CM.CategoryName,SCM.SubCategoryName
from BookMaster BM,CategoryMaster CM,SubCategoryMaster SCM
where BM.CategoryName=CM.Oid and BM.SubCategoryName=SCM.Oid
order by CM.CategoryName
this query gives me all 10 records. But, this query is fine when records in table are less. But when records goes on increasing, It will be difficult to show all records. For this reason, I want to show Top 5 books from each category.
I have tried it with group by clause
select top 5 BM.BookName ,BM.BookImage,CM.CategoryName,SCM.SubCategoryName
from BookMaster BM,CategoryMaster CM,SubCategoryMaster SCM
where BM.CategoryName=CM.Oid and BM.SubCategoryName=SCM.Oid
group by CM.CategoryName
but it gives me error saying,
Column 'BookMaster.BookName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Suggest me any solution for this.
Thanks in advance
Write a function that takes CategoryName and returns top 5 books for that category as a table
Then use T SQL Apply to print your desired result
More more details http://msdn.microsoft.com/en-us/library/ms175156%28v=sql.105%29.aspx
Try this:
WITH CategoryCTE AS (
SELECT
BookName,
ROW_NUMBER() OVER (
PARTITION BY CategoryName
ORDER BY CategoryName DESC
) AS CTE_Order
FROM BookMaster
)
SELECT bm.BookName, cm.CategoryName, scm.SubCategoryName
FROM
CategoryCTE
INNER JOIN BookMaster bm ON CategoryCTE.BookName = bm.BookName
INNER JOIN CategoryMaster cm ON bm.CategoryName = cm.Oid
INNER JOIN SubCategoryMaster scm ON bm.SubCategoryName = scm.Oid
WHERE CategoryCTE.CTE_Order < 6
GROUP BY cm.CategoryName, scm.SubCategoryName, bm.BookName
Please look over this link for solution
http://sqlzoo.net/howto/source/z.dir/err979/sqlserver
While using group by clause in query you have to specify the selected list of columns in select query in group clause, Otherwise its showing error what you get

T-SQL query to get # of something for a given category, via lookup table

I've got three tables, two are "data" tables, one is a join (or lookup) table.
Place Table
PlaceId
Name
etc...
Categories Table
CatId
Name
etc...
PlaceCats Table
PlaceId
CatId
(with appropriate relationships defined between each Id field)
What I want to do is pull the categories that contain less than 5 Places... for some reason I just can wrap my mind around the T-SQL to make that happen.
SELECT *
FROM Categories
WHERE CatId IN
(
SELECT CatId
FROM PlaceCats
GROUP BY CatId
HAVING COUNT(*) < 5
)
To get the raw data:
select CatID, count(*)
from PlaceCats
group by CatID
having count(*) < 5

Resources