Distinct over one column with value comparing on another column ICriteria NHibernate - nhibernate

I have table and object called Person. I have problem to create a distinct (over column "lastname") criteria. I want to get only the oldest Person with distinct lastnames.
For example i have (properties: firstname, lastname, age):
John Smith, 52
Jessica Smith, 45
Ann Pit, 21
Brad Pit, 30
Can anybody help me to create criteria which result i get Person object with John Smith and Brad Pit?

Probably the best approach here is to use EXISTS to filter the result set, first a SQL example to get the logic correct:
DECLARE #Person TABLE (
Id INT,
Firstname VARCHAR(20),
Lastname VARCHAR(20),
Age INT
)
INSERT INTO #Person VALUES (1, 'Brad', 'Pitt', 42)
INSERT INTO #Person VALUES (2, 'Angelina', 'Pitt', 45)
INSERT INTO #Person VALUES (3, 'John', 'Smith', 50)
INSERT INTO #Person VALUES (4, 'Jane', 'Smith', 55)
SELECT P.* FROM #Person P
WHERE EXISTS(
SELECT SUB.LastName, MAX(SUB.Age) as Age FROM #Person SUB
GROUP BY SUB.LastName
HAVING SUB.LastName = P.LastName AND MAX(SUB.Age) = P.Age)
This yields the following results which is as expected:
Id Firstname Lastname Age
-------------------------------
2 Angelina Pitt 45
4 Jane Smith 55
Now to convert to nHibernate, this effectively builds the same query as above:
var subQuery = DetachedCriteria.For<Person>("SUB")
.SetProjection(Projections.ProjectionList()
.Add(Projections.GroupProperty("LastName"), "Lastname")
.Add(Projections.Max("Age"), "Age"))
.Add(Restrictions.EqProperty(Projections.Max("Age"), "P.Age")
.Add(Restrictions.EqProperty("LastName", "P.LastName"));
return session.CreateCriteria<Person>("P")
.Add(Subqueries.Exists(subQuery))
.List<Person>();

Related

Get all results in a single row

When I take a 'SELECT *' query from a table I would like all the results to be displayed in a single 'string' format.
For example:
SELECT * FROM Employees;
Returns:
Id FirstName LastName Age
1 John Smith 30
Instead I would like to get:
Id=1,FirstName=John,LastName=Smith,Age=30
But, if I do exactly the same for the query: SELECT * FROM Cars;
I want this query to adapt and just dynamically gets the columns from the table 'Cars' and do the same with it.
Does one of this select meets your requirements ?
Declare #Employees table(Id integer, FirstName varchar(100), LastName varchar(100), Age integer)
insert into #Employees values (1, 'John', 'Smith', 30), (2, 'John', 'Doe', 23)
select CONCAT('Id=', Id, ', FirstName=', FirstName, ', LastName=', LastName, ', Age=', Age) as Employees from #Employees
select
STUFF ((
select CONCAT('; ', 'Id=', Id, ', FirstName=', FirstName, ', LastName=', LastName, ', Age=', Age) from #Employees
FOR XML PATH('')),1,2, '') as employees
OUTPUT :
Employees
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Id=1, FirstName=John, LastName=Smith, Age=30
Id=2, FirstName=John, LastName=Doe, Age=23
Employees
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Id=1, FirstName=John, LastName=Smith, Age=30; Id=2, FirstName=John, LastName=Doe, Age=23
i don't have the Employees table so i made my own in a variable, but don't mind this, you can test this code without modifying the requests
I want to add that it's code I will use in a trigger, I will be using the 'inserted' and 'deleted' tables. This makes it much harder since I'm not able to use them in a stored procedure.

Check address voor 2 properties and display in same row

From the Persons table I would like to get the following output:
Number FirstName AddressAvenue AddressFloor
----------------------------------------------
1 David Long Avenue 5th Floor
2 Bob Short Avenue NULL
3 Peter Middle Avenue 1st Floor
(Apparently, Bob his address does not contain a Floor number).
I thought I would get this by running the following query:
select
p.Number
p.FirstName
, case when (p.Street like '%Avenue%') then p.Street end as AddressAvenue
, case when (p.Street like '%Floor%') then p.Street end as AddressFloor
from
#persons
;
However, the output is as follows:
Number FirstName AddressAvenue AddressFloor
----------------------------------------------
1 David Long Avenue NULL
2 Bob Short Avenue NULL
3 Peter Middle Avenue NULL
1 David NULL 5th Floor
3 Peter NULL 1st Floor
Question How can I get both Address and Floor on the same line?
Any help is greatly appreciated!
Try this bad boy
CREATE TABLE #persons
(
Number INT
,FirstName VARCHAR(10)
,Street VARCHAR(50)
)
INSERT #persons
VALUES
(1, 'David', 'Long Avenue'),
(2, 'Bob', 'Short Avenue'),
(3, 'Peter', 'Middle Avenue'),
(1, 'David', '5th Floor'),
(3, 'Peter', '1st Floor')
--This is the code you really want, I just needed the rest to test it and make sure it worked
SELECT DISTINCT
z.Number
,z.FirstName
,(SELECT p.Street FROM #persons p where p.Street LIKE '%Avenue%' AND p.Number = z.Number)
,(SELECT p.Street FROM #persons p where p.Street LIKE '%Floor%' AND p.Number = z.Number)
FROM #persons z
DROP TABLE #persons
Results in the following:

Matching First and Last Name on two different tables

I am trying to match the first name varchar (50) and last name varchar(50) from table A to the first name varchar(50) and last name varchar(50) on table B. The issue is that both table contain a lot of shortened first names like the name Andrew in table A and there might be a matching record with the last name but the first name is Andy so it comes up as not a match. Is there anyway to get around this in SQL. The shortened names is a vice verse problem meaning that both Table A and Table B have some shortened names.
Here are some more examples:
This is my current code.
Select *
FROM TableA p
JOIN TableB e ON e.CompanyNumber = 1 and e.LastName like '%' + rtrim(ltrim(p.lastname)) + '%'
and e.FirstName like '%' + ltrim(rtrim(p.firstname)) + '%'
NOTE: This is the only way to match the tables together.
Create a third table that associates Long-form and short-form names.
For examle:
Long Form Short Form
Andrew Andy
Andrew Drew
David Dave
William Will
William Bill
William Billy
William Willy
Provided you use a 3rd Table to hold you Long/Short Names as so.
CREATE TABLE TableNames
([Id] int, [OfficialName] varchar(7), [Alias] varchar(7))
;
INSERT INTO TableNames
([Id], [OfficialName], [Alias])
VALUES
(1, 'Andrew', 'Andy'),
(2, 'Andrew', 'Andrew'),
(3, 'William', 'Bill'),
(4, 'William', 'William'),
(5, 'David', 'Dave'),
(6, 'David', 'David')
The following query should give you what you are looking for.
SELECT *
FROM (
SELECT TableA.Id AS T1_Id
,CompanyId AS T1_CompanyId
,FirstName AS T1_FirstName
,LastName AS T1_LastName
,TableNames.OfficialName AS OfficialName
FROM tableA
INNER JOIN tableNames ON TableA.FirstName = TableNames.Alias
) T1
,(
SELECT tableB.Id AS T2_Id
,CompanyId AS T2_CompanyId
,FirstName AS T2_FirstName
,LastName AS T2_LastName
,TableNames.OfficialName AS OfficialName
FROM tableB
INNER JOIN tableNames ON TableB.FirstName = TableNames.Alias
) T2
WHERE T1.T1_CompanyId = T2.T2_CompanyId
AND T1.OfficialName = T2.OfficialName
AND T1.T1_LastName = T2.T2_LastName
I set up my solution sqlfiddle at http://sqlfiddle.com/#!3/64514/2
I hope this helps.
Select *
<br>FROM TableA pJOIN TableB e
<br>ON e.CompanyNumber = 1
<br>and e.LastName like '%' + rtrim(ltrim(p.lastname)) + '%'
<br>OR
<br>e.FirstName like '%' + ltrim(rtrim(p.firstname)) + '%'
Now this depends how you determine it is match,
example:
TableA:
--------
Rownum FristName LastName
1 Andy Smith
2 Andy Mathew
TableB:
--------
Rownum FristName LastName
1 Logan Andy
2 Mathew Andy
Now will you consider first record from both the tables as a match
What about the second record in both the tables?
Basing on this we can even change the query

Combining more than one piece of data in a cell. sql

This is for a Homework assignment, but I want to go a step farther.
Let me show my Tables then I'll ask my question.
Table -- Students
StudentID PK, LastName, FirstName,
Table -- Courses
CourseID PK, CourseName
Table -- Registrations
StudentID FK, CourseID FK
The question is How can I add more than one CourseName in that specific cell? For Example I have one student who is taking 3 classes, can I show all 3 CourseNames for that particular student in the same cell in the same row?
Example.......
123456, Smith, John, English, Math, Science
Sorry if this seems simplistic but I just can't find what I'm looking for after searching.
You don't put them into 1 cell.
It will be 3 rows. An example will make this a bit more clear:
John Smith: ID 1025
Math ID 2500
English ID 2585
Violin ID 3250
In your database you will get the following rows:
StudentID CourseID
1025 2500
1025 2585
1025 3250
Well in the spirit of Christmas you can always imagine it's a turkey and STUFF it..
DECLARE #Students TABLE(StudentID INT, LastName VARCHAR(50), FirstName VARCHAR(50))
DECLARE #Courses TABLE(CourseID INT, CourseName VARCHAR(50))
DECLARE #Registrations TABLE(StudentID INT, CourseID INT)
INSERT INTO #Students VALUES
(123456, 'John', 'Smith'),(123457, 'Adrian', 'Sullivan'),(123458, 'Dude', 'Guy')
INSERT INTO #Courses VALUES
(1,'English'),(2,'Math'),(3,'Science')
INSERT INTO #Registrations VALUES
(123456,1),(123456,2),(123456,3),(123457,1),(123457,2),(123458,3)
DECLARE #STID INT
SELECT *, STUFF((SELECT ','+C2.CourseName
FROM #Registrations R2
INNER JOIN #Courses C2 ON C2.CourseID = R2.CourseID
WHERE R2.StudentID = S.StudentID
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '') [AllText]
FROM #Students S
For more reading on STUFF

SQL SELECT distinct rows from a table by multiple columns ignoring columns order (significance)

I have a table People (First_Name, Last_Name). This table has records that are duplicated as in the example (not all rows are duplicated):
First_Name Last_Name
John Smith
Alec Baldwin
Smith John
Angelo Gordon
Mary Bush
Bush Mary
How do I select all distinct people? In the final output of the query John Smith should appear only once (it’s not import if in the final query there is John Smith or Smith John).
Thank you.
Just pick an ordering and apply it across everyone. Then use a union that will eliminate duplicates anyway
select FirstName,LastName from People where FirstName <= LastName
union
select LastName,FirstName from People where LastName < FirstName
This is one way to do it using pretty much any SQL flavor.
DECLARE #Names TABLE (
First_Name VARCHAR(32)
, Last_Name VARCHAR(32)
)
INSERT INTO #Names VALUES ('John', 'Smith')
INSERT INTO #Names VALUES ('Alec', 'Baldwin')
INSERT INTO #Names VALUES ('Smith', 'John')
INSERT INTO #Names VALUES ('Angelo', 'Gordon')
INSERT INTO #Names VALUES ('Mary', 'Bush')
INSERT INTO #Names VALUES ('Bush', 'Mary')
Using a JOIN
SELECT n1.*
FROM #Names n1
LEFT OUTER JOIN #Names n2 ON n2.First_Name = n1.Last_Name
AND n2.Last_Name = n1.First_Name
AND n2.First_Name < n1.First_Name
WHERE n2.First_Name IS NULL
or NOT EXISTS
SELECT n1.*
FROM #Names n1
WHERE NOT EXISTS (
SELECT *
FROM #Names n2
WHERE n2.First_Name = n1.Last_Name
AND n2.Last_Name = n1.First_Name
AND n2.First_Name < n1.First_Name
)
Sorry was missundertanding your question on the first try...
WITH People (Firstname, Lastname)
AS
(
SELECT 'John' AS Firstname, 'Smith' AS Lastname UNION
SELECT 'John' AS Firstname, 'Smith' AS Lastname UNION
SELECT 'Alec' AS Firstname, 'Baldwin' AS Lastname UNION
SELECT 'Smith' AS Firstname, 'John' AS Lastname UNION
SELECT 'John' AS Firstname, 'Smith' AS Lastname UNION
SELECT 'Angelo' AS Firstname, 'Gordon' AS Lastname UNION
SELECT 'Mary' AS Firstname, 'Bush' AS Lastname UNION
SELECT 'Bush' AS Firstname, 'Mary' AS Lastname
)
SELECT p1.* FROM People p1
LEFT OUTER JOIN People p2 ON p2.Firstname = p1.Lastname AND p2.Lastname = p1.Firstname AND p2.Firstname < p1.Firstname
WHERE p2.Firstname IS NULL
Here's a solution which uses Oracle functions. Other flavours of SQL will have the same or very similar functions:
SQL> select * from t23
2 /
FIRST_NAME LAST_NAME
------------------------------ ------------------------------
John Smith
Alec Baldwin
Smith John
Angelo Gordon
Mary Bush
Bush Mary
6 rows selected.
SQL> select distinct least(first_name, last_name)
2 , greatest(first_name, last_name)
3 from t23
4 /
LEAST(FIRST_NAME,LAST_NAME) GREATEST(FIRST_NAME,LAST_NAME)
------------------------------ ------------------------------
Alec Baldwin
Bush Mary
John Smith
Angelo Gordon
SQL>
I think this might work in MS-SQL
select * from People
where (FirstName + "," + LastName) <> (LastName + "," + FirstName)
Another sugestion
Temporary Table:
DECLARE #Names TABLE (
First_Name VARCHAR(32)
, Last_Name VARCHAR(32)
)
INSERT INTO #Names VALUES ('John', 'Smith')
INSERT INTO #Names VALUES ('Alec', 'Baldwin')
INSERT INTO #Names VALUES ('Smith', 'John')
INSERT INTO #Names VALUES ('Angelo', 'Gordon')
INSERT INTO #Names VALUES ('Mary', 'Bush')
INSERT INTO #Names VALUES ('Bush', 'Mary')
Using CASE
SELECT DISTINCT
CASE WHEN First_Name <= Last_Name THEN First_Name ELSE Last_Name END AS First_Name,
CASE WHEN First_Name <= Last_Name THEN Last_Name ELSE First_Name END AS Last_Name
FROM #Names