Stuck in writing sql query - sql

i have a table where termid,termversion are two primary key.
column present in table - termid,termversion,name
I want to select all term whose name ilike '%AB%' and the result should contain each matching term with maximum version number.
Example:
id name ver
1 ABBBB 1
1 ABBBB 2
1 ABBBB 3
2 ABC 1
2 ABC 2
output should come
1 ABBBB 3
2 ABC 2
I want to write this query in hibernate using
Criteria...if any one can suggest me in hibernate then its really good else at least help me in writing the sql query.
PS I am using postgresql

I think that is what you are looking for:
SELECT id, name, MAX(ver)
FROM table
WHERE name ILIKE '%AB%'
GROUP BY name, id -- I assume: id == id' <==> name == name'
is it?

select id, name, max(ver) from mytable where name like '%AB%' group by id, name

can you try this sql command.
select id,name,max(ver) from table_name group by id, name having name like '%AB%'

Related

How to select the record with two different postcode in ms access with sql query

I'm new in sql script. I'm currently trying to write a sql script to select the record that with two different postcode from a table in ms access with sql query. For some reason this is just not working for me.
Example:
I have the following table resident_postcode :
Postcode Name
1001 Alan
1002 James
1003 Alan
1004 Merry
1001 Merry
I write a sql script to select the name that have 2 different postcode and looking for the output like following:
Name
Alan
Merry
I have tried to run the following script but for some reason this is just not working in MS Acess:
SELECT a.Name
FROM resident_postcode a
WHERE 1 < (SELECT count(b.Postcode) FROM resident_postcode b WHERE b.Name= a.NameGROUP BY b.Name)
Does anyone know what is going wrong with my script?
Try with:
SELECT [Name]
FROM resident_postcode
GROUP BY [Name]
HAVING Count(*) > 1
If there is no repetition of same postcode for any name then you can have names with two post codes as below
SELECT NAME FROM RESIDENT_POSTCODE
GROUP BY NAME
HAVING COUNT(POSTCODE)=2
But if any postcode can be specified more than once (for example 1001 is specified more than once for Alan) then you need to use below query:
select name from (
SELECT distinct NAME, postcode FROM RESIDENT_POSTCODE)
group by name
having count(*)=2
if you want all names having two or more than 2 postcode then use below query:
select name from (
SELECT distinct NAME, postcode FROM RESIDENT_POSTCODE)
group by name
having count(*)>=2
If you want 2 or more different post codes, then you can use:
SELECT NAME
FROM RESIDENT_POSTCODE
GROUP BY NAME
HAVING MIN(POSTCODE) <> MAX(POSTCODE);
If you want exactly two, then you can use:
SELECT NAME
FROM (SELECT DISTINCT NAME, POSTCODE
FROM RESIDENT_POSTCODE
) AS NP
GROUP BY NAME
HAVING COUNT(*) = 2;

SQL - Set field value based on count of previous rows values

I have the following table structure in Microsoft SQL:
ID Name Number
1 John
2 John
3 John
4 Mark
5 Mark
6 Anne
7 Anne
8 Luke
9 Rachael
10 Rachael
I am looking to set the 'Number' field to the number of times the 'Name' field has appeared previously, using SQL.
Desired output as follows:
ID Name Number
1 John 1
2 John 2
3 John 3
4 Mark 1
5 Mark 2
6 Anne 1
7 Anne 2
8 Luke 1
9 Rachael 1
10 Rachael 2
The table is ordered by 'Name', so there is no worry of 'John' appearing under ID 11 again, using my example.
Any help would be appreciated. I'm not sure if I can do this with a simple SELECT statement, or whether I will need an UPDATE statement, or something more advanced.
Use ROW_NUMBER:
SELECT ID, Name,
ROW_NUMBER() OVER (PARTITION BY Name
ORDER BY ID) AS Number
FROM mytable
There is no need to add a field for this, as the value can be easily calculated using window functions.
You should be able to use the ROW_NUMBER() function within SQL Server to partition each group (by their Name property) and output the individual row in each partition :
SELECT ID,
Name,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY ID) AS Number
FROM YourTable
ORDER BY ID
You can see what your data looks like prior to the query :
and then after it is executed :
If your system doesnt support OVER PARTITION, you can use following code:
SELECT
ID,
Name,
(
SELECT
SUM(counterTable.nameCount)
FROM
mytable innerTable
JOIN (SELECT 1 as nameCount) as counterTable
WHERE
innerTable.ID <= outerTable.ID
AND outerTable.Name = innerTable.Name
) AS cumulative_sum
FROM
mytable outerTable
ORDER BY outerTable.ID
Following CREATE TABLE statement I used and then filled in your data:
CREATE TABLE `mytable` (
`ID` INT(11) NULL DEFAULT NULL,
`Name` VARCHAR(50) NULL DEFAULT NULL
);
This should work with DBS not supporting OVER PARTITION like MySQL, Maria, ...

SQL - Removing Duplicate without 'hard' coding?

Heres my scenario.
I have a table with 3 rows I want to return within a stored procedure, rows are email, name and id. id must = 3 or 4 and email must only be per user as some have multiple entries.
I have a Select statement as follows
SELECT
DISTINCT email,
name,
id
from table
where
id = 3
or id = 4
Ok fairly simple but there are some users whose have entries that are both 3 and 4 so they appear twice, if they appear twice I want only those with ids of 4 remaining. I'll give another example below as its hard to explain.
Table -
Email Name Id
jimmy#domain.com jimmy 4
brian#domain.com brian 4
kevin#domain.com kevin 3
jimmy#domain.com jimmy 3
So in the above scenario I would want to ignore the jimmy with the id of 3, any way of doing this without hard coding?
Thanks
SELECT
email,
name,
max(id)
from table
where
id in( 3, 4 )
group by email, name
Is this what you want to achieve?
SELECT Email, Name, MAX(Id) FROM Table WHERE Id IN (3, 4) GROUP BY Email;
Sometimes using Having Count(*) > 1 may be useful to find duplicated records.
select * from table group by Email having count(*) > 1
or
select * from table group by Email having count(*) > 1 and id > 3.
The solution provided before with the select MAX(ID) from table sounds good for this case.
This maybe an alternative solution.
What RDMS are you using? This will return only one "Jimmy", using RANK():
SELECT A.email, A.name,A.id
FROM SO_Table A
INNER JOIN(
SELECT
email, name,id,RANK() OVER (Partition BY name ORDER BY ID DESC) AS COUNTER
FROM SO_Table B
) X ON X.ID = A.ID AND X.NAME = A.NAME
WHERE X.COUNTER = 1
Returns:
email name id
------------------------------
jimmy#domain.com jimmy 4
brian#domain.com brian 4
kevin#domain.com kevin 3

How to select the top n from a union of two queries where the resulting order needs to be ranked by individual query?

Let's say I have a table with usernames:
Id | Name
-----------
1 | Bobby
20 | Bob
90 | Bob
100 | Joe-Bob
630 | Bobberino
820 | Bob Junior
I want to return a list of n matches on name for 'Bob' where the resulting set first contains exact matches followed by similar matches.
I thought something like this might work
SELECT TOP 4 a.* FROM
(
SELECT * from Usernames WHERE Name = 'Bob'
UNION
SELECT * from Usernames WHERE Name LIKE '%Bob%'
) AS a
but there are two problems:
It's an inefficient query since the sub-select could return many rows (looking at the execution plan shows a join happening before top)
(Almost) more importantly, the exact match(es) will not appear first in the results since the resulting set appears to be ordered by primary key.
I am looking for a query that will return (for TOP 4)
Id | Name
---------
20 | Bob
90 | Bob
(and then 2 results from the LIKE query, e.g. 1 Bobby and 100 Joe-Bob)
Is this possible in a single query?
You could use a case to place the exact matches on top:
select top 4 *
from Usernames
where Name like '%Bob%'
order by
case when Name = 'Bob' then 1 else 2 end
Or, if you're worried about performance and have an index on (Name):
select top 4 *
from (
select 1 as SortOrder
, *
from Usernames
where Name = 'Bob'
union all
select 2
, *
from Usernames
where Name like '%Bob%'
and Name <> 'Bob'
and 4 >
(
select count(*)
from Usernames
where Name = 'Bob'
)
) as SubqueryAlias
order by
SortOrder
A slight modification to your original query should solve this. You could add in an additional UNION that matches WHERE Name LIKE 'Bob%' and give this priority 2, changing the '%Bob' priority to 3 and you'd get an even better search IMHO.
SELECT TOP 4 a.* FROM
(
SELECT *, 1 AS Priority from Usernames WHERE Name = 'Bob'
UNION
SELECT *, 2 from Usernames WHERE Name LIKE '%Bob%'
) AS a
ORDER BY Priority ASC
This might do what you want with better performance.
SELECT TOP 4 a.* FROM
(
SELECT TOP 4 *, 1 AS Sort from Usernames WHERE Name = 'Bob'
UNION ALL
SELECT TOP 4 *, 2 AS Sort from Usernames WHERE Name LIKE '%Bob%' and Name <> 'Bob'
) AS a
ORDER BY Sort
This works for me:
SELECT TOP 4 * FROM (
SELECT 1 as Rank , I, name FROM Foo WHERE Name = 'Bob'
UNION ALL
SELECT 2 as Rank,i,name FROM Foo WHERE Name LIKE '%Bob%'
) as Q1
ORDER BY Q1.Rank, Q1.I
SET ROWCOUNT 4
SELECT * from Usernames WHERE Name = 'Bob'
UNION
SELECT * from Usernames WHERE Name LIKE '%Bob%'
SET ROWCOUNt 0
The answer from Will A got me over the line, but I'd like to add a quick note, that if you're trying to do the same thing and incorporate "FOR XML PATH", you need to write it slightly differently.
I was specifying XML attributes and so had things like :
SELECT Field_1 as [#attr_1]
What you have to do is remove the "#" symbol in the sub queries and then add them back in with the outer query. Like this:
SELECT top 1 a.SupervisorName as [#SupervisorName]
FROM
(
SELECT (FirstNames + ' ' + LastName) AS [SupervisorName],1 as OrderingVal
FROM ExamSupervisor SupervisorTable1
UNION ALL
SELECT (FirstNames + ' ' + LastName) AS [SupervisorName],2 as OrderingVal
FROM ExamSupervisor SupervisorTable2
) as a
ORDER BY a.OrderingVal ASC
FOR XML PATH('Supervisor')
This is a cut-down version of my final query, so it doesn't really make sense, but you should get the idea.

Counting values in columns

What I am looking for is to group by and count the total of different data in the same table and have them show in two different columns. Like below.
Data in table A
Fields:
Name Type
Bob 1
John 2
Bob 1
Steve 1
John 1
Bob 2
Desired result from query:
Name Type 1 Type 2
Bob 2 1
John 1 1
Steve 1 0
This will do the trick in SQL Server:
SELECT
name,
SUM( CASE type WHEN 1 THEN 1 ELSE 0 END) AS type1,
SUM( CASE type WHEN 2 THEN 1 ELSE 0 END) AS type2
FROM
myTable
GROUP BY
name
No time to write the code, but the Case statement is what you want here. SImply havea value of 1 if it meets the case and zero if it deosn't. Then you can sum the columns.
Use two separate GROUP BY subqueries.
SELECT Name, a.Count1, b.Count2
from myTable
JOIN
(SELECT Name, SUM(Type) AS Count1 FROM myTable GROUP BY Name WHERE Type=1) AS a ON a.Name = myTable.Name
(SELECT Name, SUM(Type) FROM myTable GROUP BY Name WHERE Type=2) AS b ON b.Name = myTable.Name
You're looking for a CrossTab solution. The above solutions will work, but you'll come unstuck if you want a general solution and have N types.
A CrossTab solution will solve this for you. If this is for quickly crunching some numbers then dump your data into Excel and use the native Pivot Table feature.
If it's for a RDBMS in an app, then it depends upon the RDBMS. MS SQL 2005 and above has a crosstab syntax. See:
http://www.databasejournal.com/features/mssql/article.php/3521101/Cross-Tab-reports-in-SQL-Server-2005.htm
#Seb has a good solution, but it's server-dependent. Here's an alternate using subselects that should be portable:
select
name,
(select count(type) from myTable where type=1 and name=a.name) as type1,
(select count(type) from myTable where type=2 and name=a.name) as type2
from
myTable as a
group by
name