I have three Tables :
tbl_Publisher [Publisher_ID, addr,account-num,...,city];
tbl_Title [Title_ID, frequency, publisher,.., Publisher_ID];
tbl_Invoice [Invoice_ID, ordered_Date,...,Title_ID];
I would like to return a list of Titles by Publisher and each Title has the count number of Invoices it contains. in one result set.
I'm using a stored procedure as following :
PROCEDURE [dbo].[usp_GetTitlesbyPublisher]
-- Add the parameters for the stored procedure here
#PublisherID INT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
-- Insert statements for procedure here
SELECT Title_ID,TitleName,pub_type,Frequency , Holdings ,tbl_Title.publisher ,section ,tbl_Title.Publisher_ID from tbl_Title, tbl_Publisher
where tbl_Title.Publisher_ID = tbl_Publisher.Publisher_ID
and #PublisherID = tbl_Publisher.Publisher_ID
END
How can I return the number of Invoice by each Title ?
You can probably accomplish this with a GROUP BY:
SELECT t.Title_ID, t.TitleName, p.pub_type,
t.Frequency, Holdings, t.publisher, section,
t.Publisher_ID, count(i.Invoice_ID) as NoOfInvoices
from tbl_Title t
inner join tbl_Publisher p on t.Publisher_ID = p.Publisher_ID
left join tbl_Invoice i on i.Title_ID = t.Title_ID
where #PublisherID = p.Publisher_ID
group by t.Title_ID, t.TitleName, p.pub_type, t.Frequency,
Holdings, t.publisher, section, t.Publisher_ID
Not checked the syntax on this.
SELECT COUNT(tbl_Invoice.Invoice_ID) 'InvoiceCount',Title_ID,TitleName,pub_type,Frequency, Holdings ,tbl_Title.publisher ,section ,tbl_Title.Publisher_ID
FROM tbl_Title
INNER JOIN tbl_Publisher ON tbl_Publisher.Publisher_ID = tbl_Title.Publisher_ID
INNER JOIN tbl_Invoice ON tbl_Invoice.Invoice_ID = tbl_Title.Invoice_ID
WHERE tbl_Publisher.Publisher_ID = #PublisherID
GROUP BY
Title_ID,TitleName,pub_type,Frequency, Holdings ,tbl_Title.publisher ,section ,tbl_Title.Publisher_ID
Related
I'm trying to use the SQL operator CONTAINSTABLE to get a list of search results, like this:
SELECT c.*, ccontains.[RANK]
FROM Customers c
INNER JOIN CONTAINSTABLE(Customers, LastName, #searchTerm) ccontains ON c.Id = ccontains.[KEY]
And calling this function from EF Core 2.1:
var query = DbContext.Customers.FromSql("SELECT * FROM udfSearchCustomers(#searchTerm)",
new SqlParameter(#searchTerm, mySearchTerm));
query = query.Include(c => c.Addresses).Take(maxResults);
I want to order my search results descending by RANK, to get the most relevant results at the top. Adding an ORDER BY ccontains.[RANK] to my function is not allowed, as my SELECT * FROM udfSearchCustomers(...) will be wrapped by EF Core: ORDER BY is not allowed on an inner query. Adding query.OrderBy(c => c.Rank) is not possible, as RANK is not on the Customer entity.
I've tried using System.Linq.Dynamic, as well as other reflection solutions, to do this:
query = query.OrderBy("Rank");
But I got an exception:
"Rank" is not a member of type "Customer"
which is true. Is there any way to order on a column not on an entity, or will I need to create a MyCustomerSearchQuery query object and use AutoMapper to convert those to Customer? I'd rather not, as Customer has many properties and keeping those in sync will be a hassle.
Thanks in advance!
you can try with
query = query.OrderBy(x => x.Rank);
OR
query = query.OrderBy(x => x["Rank"]);
You can create the stored procedure of the query which takes two parameter : #searchKey, #orderByColumn.
CREATE PROCEDURE [dbo].[UdfSearchCustomers]
#searchTerm varchar(50),
#orderByColumn varchar(50)
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
SET #sql =' SELECT c.*, ccontains.[RANK]
FROM Customers c
INNER JOIN CONTAINSTABLE(Customers, LastName, ''#searchTerm'') ccontains
ON c.Id = ccontains.[KEY]
ORDER BY #orderByColumn'
SET #sql = REPLACE(#sql, '#orderByColumn', #orderByColumn)
SET #sql = REPLACE(#sql, '#searchTerm', #searchTerm)
exec sp_executesql #sql
END
GO
Then you can query the same stored procedure as:
var query = DbContext.Customers.FromSql("exec UdfSearchCustomers #p0, #p1", mySearchTerm, "Rank");
If you want to add join to the address table then you can add the join to the stored procedure. This may give you your desired result.
I tried to set a value to variable in sub query but it doesn't work.
Here is my query:
declare #val1 int
declare #val2 int
select #val1 = sum(column1)
,(select #val2 = (select sum(column2) from table2))
,(#val1+#val2)Result
from table 1
What I want to do is setting #val2 for sub query help me please
I meant set in Sub query not separate select statement
Just use 3 separate selects:
select #val1 = sum(column1) from table1
select #val2 = sum(column2) from table2
select (#val1+#val2) as Result
Or you can also write 2 selects:
select #val1 = sum(column1),
#val2 = (select SUM(column2) from table2)
from table1
select (#val1 + #val2) Result
But not just 1 select:
A SELECT statement that assigns a value to a variable must not be
combined with data-retrieval operations
If you need to accomplish all in one select and return a recordset, do not use variables, do it like this:
SELECT sum1 + sum2 FROM (
select sum(column1) as sum1,
(select SUM(column2) from table2) as sum2
from table1
) subquery
I am trying to use a internal SQL command to query a table and use the result to query another but am getting the following problem
"Msg 137, Level 16, State 1, Line 10
Must declare the scalar variable "#ListofPropIDs"."
Any help would be appreciated
DECLARE #ListofPropIDs TABLE(IDs VARCHAR(100));
INSERT INTO #ListofPropIDs
SELECT Id
FROM Property
WHERE CreatedBy = 'oliver#test.co.uk'
SELECT
COUNT (Digits)
FROM dbo.CallInfo
WHERE Digits = #ListofPropIDs;
GO
DECLARE #ListofPropIDs TABLE(IDs VARCHAR(100));
INSERT INTO #ListofPropIDs
SELECT Id
FROM Property
WHERE CreatedBy = 'oliver#test.co.uk'
SELECT
COUNT (Digits)
FROM dbo.CallInfo C
INNER JOIN #ListofPropIDs s
on s.IDs = c.Digits
without knowing what you want to achieve, something like this should work but may not be correct:
DECLARE #ListofPropIDs TABLE(IDs VARCHAR(100));
INSERT INTO #ListofPropIDs
SELECT Id
FROM Property
WHERE CreatedBy = 'oliver#test.co.uk'
SELECT
COUNT (Digits)
FROM dbo.CallInfo
WHERE Digits in (SELECT IDs FROM #ListofPropIDs)
Your original query is trying to use a table variable as part of a where clause as if it where a column which is not correct.
#ListofPropIDs is a table and you're using it like a Value.
use :
SELECT
COUNT (Digits)
FROM dbo.CallInfo
WHERE Digits IN ( SELECT IDs from #ListofPropIDs)
GO
You can't use a table as where condition value
Instead you can use SQL: IN Condition
SELECT COUNT (Digits)
FROM dbo.CallInfo
WHERE Digits IN (Select Id From #ListofPropIDs)
Or use Inner Join
SELECT COUNT (Digits)
FROM dbo.CallInfo C
Inner Join #ListofPropIDs T On T.Id=C.Digits
Basically i have 3 tables like this (with many to many relationship);
And i am querying searching like this;
ALTER PROC [dbo].[usp_ContactSearch]
(
#PersonName varchar(60)= '',
#MobileNo varchar(20)= '',
#Nationlity varchar(50)='' ,
#ContactTypes varchar(max) = ''
)
AS
BEGIN
SELECT DISTINCT c.ContactId, c.PersonName, ct.ContactType, ct.ContactTypeId
FROM Contact c
LEFT OUTER JOIN ContactWithContactType cct
ON c.ContactId = cct.ContactId
LEFT OUTER JOIN ContactType ct
ON cct.CountactTypeId = ct.ContactTypeId
WHERE
c.PersonName LIKE CASE WHEN #PersonName='' THEN c.PersonName ELSE '%'+#PersonName+'%' END
AND
c.MobileNo1 LIKE CASE WHEN #MobileNo='' THEN c.MobileNo1 ELSE '%'+#MobileNo+'%' END
AND
c.Nationality LIKE CASE WHEN #Nationlity='' THEN c.Nationality ELSE '%'+#Nationlity+'%' END
END
So, the result data by default is;
So, from the Front End, i have ContactTypes (which are dynamic i.e comming from contact types table), and the interface looks like this
Now, whenever user check the PropertyOwner(ContactTypeId=1), The data should be filtered and only those contacts should be shown which are belong to ContactTypeId=1
Silarly, when i check the second checkbox i.e Tenant(ContactTypeId=2). The data should be more filtered and only those contacts will be displayed which belongs to ContactTypeId= 1 and 2. And similarly for 3rd ContactType, the data should be more filtered and so on and so forth.
So, the problem is ContactTypes are dynamic and i don't know how to handle this situation.
Any help regards to the query and performance is much apreciated.
Try this. This will work...
-- This is User Defined Table Type Variable
Declare #MyTypeDataType ContType
-- You will pass value to this variable from Front End
Insert into #MyTypeDataType values(1),(2),(3);
-- From Front end you will pass the
-- selected values to "Table Type Variable" and
-- also to a "Varchar" Variable
Declare #Type as Varchar(20);
SET #Type = '1,2,3';
SELECT X.* FROM
(
-- This query will get all persons,
-- who have any one Type u want to Search...
SELECT C.*,CTT.ContactType, CTT.ContactTypeId FROM Contact C
INNER JOIN ContactWithType CT
ON C.ContactId = CT.ContactId
INNER JOIN ContactType CTT
ON CTT.ContactTypeId = CT.ContactTypeId
WHERE #Type LIKE '%' + CAST( CT.ContactTypeId AS VARCHAR(MAX)) + '%'
) X
INNER JOIN
(
-- This will count the Record of each Person,
-- how many time a persons record exists..
SELECT C.ContactId, COUNT(C.ContactId) AS Total
FROM Contact C
INNER JOIN ContactWithType CT
ON C.ContactId = CT.ContactId
INNER JOIN ContactType CTT
ON CTT.ContactTypeId = CT.ContactTypeId
WHERE #Type LIKE '%' + CAST( CT.ContactTypeId AS VARCHAR(MAX)) + '%'
GROUP BY C.ContactId
)Y
ON X.ContactId = Y.ContactId
-- Filter persons
AND Y.Total = (SELECT COUNT(*) FROM #MyTypeDataType)
I would like to recommend to use split function for your query to filter ContactTypes. For example, when in your form someone check Property Owner and Tenant (contactType = 1, 2) or so on, then you can pass it to your stored proc as such
#ContactTypes varchar(max) = '1,2'
Then you can use one of the split string function that you need to create. You can refer to this excellent article (http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings).
I use the article function SplitStrings_Moden for simple string split.
Then you can use it like in your stored proc like this.
And ContactType in (select [item] from SplitStrings_Moden(#ContactTypes , ','))
As for performance wise, the example given return a table of string column which in your case, you could cast it to int for better for performance. But i guess you might to test it on your dataset if the performance is reasonable without the casting.
I would recommend using xml datatype for this. You can find more information here.
Use XML as input variable to an SP
So I have a many to many relationship between something known as Specialism and SpecialismCombo. What I'm trying to do is take an int[] of ids and check if there is a combo already that contains the specialisms with those ids.
I was close but not quite right.
Say I have specialisms with Ids 1 and 3 and I create a combo with those specialisms.
If I pass in 3 & 1 then it returns the expected combo id.
If I pass in 1 then it returns the combo id that has both 1 and 3.
I can't just rely on total number of specialisms associated with the combo. Because if a combo has two items, 1 and 4 and the items being matched on are 1 and 3 I don't want this coming back as a matched combo.
So it's like I do need the count of this result, and match the count of total specialisms associated to the combo. I don't quite get whether I'm after a subquery or detatchedcriteria or how to get the result I want using nhibernate criteria. Thanks for your help!
int[] SpecialismIds = ArrayExtensions.ConvertArray<int>(idCollection.Split(new char[] { '|' }));
ICriteria query = m_SpecialismComboRepository.QueryAlias("sc");
query.CreateAlias("sc.Specialisms", "s", NHibernate.SqlCommand.JoinType.InnerJoin);
ICriterion lastCriteria = null;
foreach(int i in SpecialismIds)
{
ICriterion currentCriteria = Restrictions.Eq("s.SpecialismId", i);
if (lastCriteria != null)
lastCriteria = Restrictions.Or(lastCriteria, currentCriteria);
else
lastCriteria = currentCriteria;
}
if (lastCriteria != null)
query.Add(lastCriteria);
IProjection IdCount = Projections.Count("s.SpecialismId").As("IdCount");
query.SetProjection(
Projections.GroupProperty("sc.SpecialismComboId"),
IdCount
);
query.Add(Restrictions.Eq(IdCount, SpecialismIds.Count()));
var comboId = query.List();
The sql being generated is:
SELECT this_.SpecialismComboId as y0_, count(s1_.SpecialismId) as y1_
FROM dbo.SpecialismCombo this_
inner join SpecialismComboSpecialism specialism3_ on this_.SpecialismComboId=specialism3_.SpecialismId
inner join dbo.Specialism s1_ on specialism3_.SpecialismComboId=s1_.SpecialismId WHERE s1_.SpecialismId = #p0
GROUP BY this_.SpecialismComboId HAVING count(s1_.SpecialismId) = #p1',N'#p0 int,#p1 int',#p0=3,#p1=1
EDIT - It seems like I either need the having to be something like...
HAVING count(s1_.SpecialismId) = (select count(SpecialismId)
from specialismComboSpecialism
where SpecialismComboId = y0
group by SpecialismComboId) == #p2
Or maybe it's simpler than that and I need to exclude SpecalismCombos where the combo.specialisms are not in the collection of ids.
Ie. if the combo has specialisms 1 and 3 but the collection only has 1.. then we could exclude this combo based on 3 not being in the collection…
Edit 8/8/2011
Went back to focusing on how to get the result I needed in SQL - and I believe this query works.
WITH CustomQuery AS
(
SELECT sc.SpecialismComboId,
count(s.SpecialismId) AS ItemCount
FROM SpecialismCombo sc
inner join SpecialismComboSpecialism scs on sc.SpecialismComboId = scs.SpecialismComboId
inner join Specialism s on s.SpecialismId = scs.SpecialismId
GROUP BY sc.SpecialismComboId
HAVING count(s.SpecialismId) = 2
)
SELECT CustomQuery.SpecialismComboId FROM CustomQuery
INNER JOIN SpecialismComboSpecialism scs on CustomQuery.SpecialismComboId = scs.SpecialismComboId
WHERE scs.SpecialismId in (1,4)
GROUP BY CustomQuery.SpecialismComboId
HAVING count(scs.SpecialismId) = 2
So now I just need to figure out how to call this procedure from my nhibernate code passing in the appropriate values :)
I also discovered in the process that my mapping class was wrong - as it was putting the wrong values in the mapping table (ie. the specialismid was ending up in the specialismcomboid field !)
Your solution should actually work well. The specialisms are filtered by id and there shouldn't be anything left that is not searched for, so count should work. Unless you have the same specialism joined more the once. This currentCriteria lastCriteria stuff looks a bit strange, may be there is an error. Just use Expression.In or Conjunction.
IProjection IdCount = Projections.Count("s.SpecialismId").As("IdCount");
IQuery query = session
.CreateCriteria<SpecialismCombo>("sc")
.CreateCriteria("Specialism", "s");
.Add(Expression.In("s.SpecialismId", SpecialismIds));
.SetProjection(
Projections.GroupProperty("sc.SpecialismComboId"),
IdCount);
.Add(Restrictions.Eq(IdCount, SpecialismIds.Count()));
Should result in a query like this:
select ...
from
SpecialismCombo sc
inner join -- linktable ...
inner join Specialism s on ...
where
s.SpecialismId in (1, 4)
Group By sc.SpecialismComboId
having count(*) = 2
The same in HQL
from SpecialismCombo sc
join sc.Specialism s
where s.id in (:ids)
group by sc
having count(*) = :numberOfIds
You could also join the specialism as many times as you have ids to find:
IQuery query = session.CreateCriteria<SpecialismCombo>("sc")
int counter = 0;
foreach(int id in ids)
{
string alias = "s" + counter++;
query
.CreateCriteria("Specialism", alias);
.Add(Expression.Eq(alias + ".SpecialismId", id));
}
should create a query like this:
select ...
from
SpecialismCombo sc
inner join -- linktable ...
inner join Specialism s0 on ...
inner join -- linktable ...
inner join Specialism s1 on ...
where
s0.SpecialismId = 1
and s1.SpecialismId = 4
So I ended up creating a stored proc and using SQL CTE in order to get only the specialism combos with the correct count of specialisms. Posting this in case someone else comes across a similar issue.
Rediscovered after 8 months of using nhibernate that I'd forgotten a lot of SQL stuff :)
DECLARE #IdCollectionCount INT
, #IdCollection VARCHAR(250)
, #CollectionDelimiter NVARCHAR
SET #IdCollectionCount = 2;
SET #IdCollection = '1,4';
SET #CollectionDelimiter= ',';
WITH CustomQuery AS
(
SELECT sc.SpecialismComboId,
count(s.SpecialismId) AS ItemCount
FROM SpecialismCombo sc
inner join SpecialismComboSpecialism scs on sc.SpecialismComboId = scs.SpecialismComboId
inner join Specialism s on s.SpecialismId = scs.SpecialismId
GROUP BY sc.SpecialismComboId
HAVING count(s.SpecialismId) = #IdCollectionCount
)
SELECT Top 1 CustomQuery.SpecialismComboId FROM CustomQuery
INNER JOIN SpecialismComboSpecialism scs on CustomQuery.SpecialismComboId = scs.SpecialismComboId
INNER JOIN dbo.fn_SplitDelimited(#IdCollection,#CollectionDelimiter) AS ids
ON scs.SpecialismId = CAST(ids.ListValue AS INT)
GROUP BY CustomQuery.SpecialismComboId
HAVING count(scs.SpecialismId) = #IdCollectionCount