How to add table column headings to sql select statement - sql

I have a SQL select statement like this:
select FirstName, LastName, Age from People
This will return me something like a table:
Peter Smith 34
John Walker 46
Pat Benetar 57
What I want is to insert the column headings into the first row like:
First Name Last Name Age
=========== ========== ====
Peter Smith 34
John Walker 46
Pat Benetar 57
Can someone suggest how this could be achieved?
Could you maybe create a temporary table with the headings and append the data one to this?

Neither of the answers above will work, unless all your names come after "first" in sort order.
Select FirstName, LastName
from (
select Sorter = 1, FirstName, LastName from People
union all
select 0, 'FirstName', 'LastName') X
order by Sorter, FirstName -- or whatever ordering you need
If you want to do this to all non-varchar columns as well, the CONS are (at least):
ALL your data will become VARCHAR. If you use Visual Studio for example, you will NO LONGER be able to recognize or use date values. Or int values. Or any other for that matter.
You need to explicitly provide a format to datetime values like DOB. DOB values in Varchar in the format dd-mm-yyyy (if that is what you choose to turn them into) won't sort properly.
The SQL to achieve this, however not-recommended, is
Select FirstName, LastName, Age, DOB
from (
select Sorter = 1,
Convert(Varchar(max), FirstName) as FirstName,
Convert(Varchar(max), LastName) as LastName,
Convert(Varchar(max), Age) as Age,
Convert(Varchar(max), DOB, 126) as DOB
from People
union all
select 0, 'FirstName', 'LastName', 'Age', 'DOB') X
order by Sorter, FirstName -- or whatever ordering you need

The lightest-weight way to do this is probably to do a UNION:
SELECT 'FirstName' AS FirstName, 'LastName' AS LastName
UNION ALL
SELECT FirstName, LastName
FROM People
No need to create temporary tables.

The UNION All is the solution except it should be pointed out that:
To add a header to a non-char column will require converting the column in the first part of the query.
If the converted column is used as part of the sort order then the field reference will have to be to the name of the column in the query, not the table
example:
Select Convert(varchar(25), b.integerfiled) AS [Converted Field]...
... Order by [Converted Field]

Related

how to unpivot the table, from column to row

I have a table like.
firstname lastname Address
emma olu lagos
i want to convert this like...
firstname emma
lastname olu
address lagos
What you are describing is "unpivoting", not pivoting.
The generic method is:
select 'firstname' as which, firstname
from t
union all
select 'lastname' as which, lastname
from t
union all
select 'address' as which, address
from t;
This assumes that the values in the columns are compatible -- meaning that they have the same type and collation.
There may be more efficient methods, depending on the database you are using. You should provide a database tag for the database you are really using.
use union all
select 'firstname',firstname from tablename
union all
select 'lastname',lastnamefrom tablename
union all
select 'address',address from tablename

Hive parse string to columns

In a Hive table, I have columns (all have string datatype)
CustomerId, Name, Gender
Name datatype is string of format
{'firstname': 'XXXXXX', 'middlename': 'YYYYYY', 'lastname': 'ZZZZZZ'}
Also, some of the rows have missing middlename -
CustomerId, {'firstname': 'AAAAAA', 'lastname': 'BBBBB'}, Gender
I wanted to create a new table and populate the below columns -
CustomerId, firstname, middlename, lastname , Gender.
Middlename will be null/spaces if value not present. Could you please help?
Those are not valid JSON strings, use double quotes instead of single quotes, then you may use JSON_TUPLE() to extract fields.
CREATE TABLE yournewtable AS
SELECT customerid,
firstname,
middlename,
lastname,
gender
FROM yourtable lateral view
json_tuple(Name,'firstname','middlename','lastname')
j as firstname, middlename,lastname;

Sql returns Column has "FristName LastName" as 1 string how to order by Lastname?

I'm using Oracle. My sql returns a column like this
Name:
John Smith
David Lee
...
If I do Order by Name, it will order by first name. How do I order by Last name? If I do Order by Lastname, Firstname oracle returns invalid identifiers. I tried substr, instr but it doesn't work. I know the sql is tedious but just want the data to quickly fix this issue.
Full SQL:
http://pastebin.com/hYkdHBDM
You say your SQL "returns a column" in that format. Do you mean the column is stored that way, or that it's stored as two fields and composed into one in the SQL statement?
If stored that way it's difficult to create an algorithm that will reliably determine what part of a multi-part name is the last name part (indeed, this is sometimes down to personal preference of the person owning the name).
If stored in two separate fields you should be able to ORDER BY LastName, FirstName depending on how the SQL is constructed and whether there are any intermediate views between you and the table. Please post the SQL and table structure.
First, in order to sort by LastName, it needs to be one of the columns you return in each of the queries in your Union All. Second, you can greatly simplify your query by using a common-table expression. Third, do not use the comma delimited syntax for Joins (e.g. From TableA, TableB, TableC...). Instead use the ISO Join syntax.
With RootQuery As
(
Select MeetingID
, FirstName || ' ' || LastName AS Name
, LastName
, CASE WHEN RSVP = 1 THEN 1 ELSE NULL END AS Yes
, CASE WHEN RSVP = 0 THEN 1 ELSE NULL END AS No
, CASE WHEN RSVP = 2 THEN 1 ELSE NULL END AS Phone
, CASE WHEN RSVP = -1 THEN 1 ELSE NULL END AS No_Reply
, MysteryTable0.Response1
, MysteryTable1.Response2
, Note
, groupname
From Attendance A
Join Allusers As B
And B.MemberId = A.PersonId
Join MembershipGroups As M
And M.MemberId = B.MemberID
Join (
SELECT TD.MEMBERID AS MEM0
, Response AS Response1
FROM TRACKINGDETAILS TD, ALLUSERS U
Where TD.MEMBERID = U.MEMBERID
And TD.TRACKINGID = 64
) MysteryTable0
On MysteryTable0.Mem0 = B.MemberId
Join (
SELECT TD.MEMBERID AS MEM1
, Response AS Response2
FROM TRACKINGDETAILS TD, ALLUSERS U
Where TD.MEMBERID = U.MEMBERID
And TD.TRACKINGID = 65
) As MysteryTable1
On MysteryTable1.Mem1 = B.MemberId
Where Meetingid = :1
)
Select MeetingId, Name, LastName, Yes, No, Phone, No_Reply
, Response1, Response2
, Note, GroupName
From RootQuery
Union All
Select Null, 'Total', LastName, SUM(Yes), SUM(No), SUM(Phone), SUM(No_Reply)
, TO_CHAR(SUM(Response1))
, TO_CHAR(SUM(Response2))
, NULL, Groupname
From RootQuery
Group By GroupName
Union All
Select Null, 'Grand Total', LastName, SUM(Yes), SUM(No), SUM(Phone), SUM(No_Reply)
, TO_CHAR(SUM(Response1))
, TO_CHAR(SUM(Response2))
,NULL, ' '
From RootQuery
Group By ???
Order By GroupName Desc, LastName Asc, Name Asc
Btw, the last query will probably have a problem in that it did not have a Group By (which I denoted with Group By ???) but you are using aggregate functions.
What Matthew PK said is correct however he failed to mention that INSTR can parse backwards in which case, his "fail" scenario would be resolved.
Here try this:
create table test_name (f_name varchar2(20), l_name varchar2(20), full_name varchar2(20));
insert into test_name (f_name, l_name, full_name) values ('John', 'Mellencamp', 'John 2Mellen');
insert into test_name (f_name, l_name, full_name) values ('John', 'Mellencamp', 'John C. 1Mellen');
select f_name, l_name, substr(full_name,instr(full_name,' ',-1,1)) as substr, full_name from test_name order by substr(full_name,instr(full_name,' ',-1,1));
Basically the money shot is: substr(full_name,instr(full_name,' ',-1,1))
If you know the field will always be "FirstName LastName" separated by a space you could:
ORDER BY RIGHT(Name, INSTR(Name,' '))
This is the number of characters, on the right side, starting at the space.
This will fail if any other names are separated by a space like "John Cougar Mellencamp"

SQL - How to display the students with the same age?

the code I wrote only tells me how many students have the same age. I want their names too...
SELECT YEAR(CURRENT DATE-DATEOFBIRTH) AS AGE, COUNT(*) AS HOWMANY
FROM STUDENTS
GROUP BY YEAR(CURRENT DATE-DATEOFBIRTH);
this returns something like this:
AGE HOWMANY
--- -------
21 3
30 5
Thank you.
TABLE STUDENTS COLUMNS:
StudentID (primary key), Name(varchar), Firstname(varchar), Dateofbirth(varchar)
I was thinking of maybe using the code above and somewhere add the function concat that will put the stundents' names on the same row as in
your existing SQL looks like it has errors, but you could use GROUP_CONCAT:
add GROUP_CONTACT(colname) as another column to fetch, then split by , in your application
The resulting data set does not appear useful on the surface based on the question unless you are looking for a listing of students, their age, and how many other students are of the same age:
SELECT NAME, AGE, HOWMANY
FROM STUDENTS AS S,
(SELECT YEAR(CURRENT DATE-DATEOFBIRTH) AS AGE,
COUNT(*) AS HOWMANY
FROM STUDENTS
GROUP BY YEAR(CURRENT DATE-DATEOFBIRTH)
) AS A
WHERE YEAR(CURRENT DATE-S.DATEOFBIRTH) = A.AGE
Basically perform a self-join with the age counts you have calculated.
What about...
SELECT name FROM students WHERE age = ENTER_AGE_HERE;
You have the names and the number of students can be found by finding the number of entries you get from the query.
For example, in PHP, you can find the length of the array.
Of course, you have to change to names in my example to the names used in your database.
CREATE TABLE #Student
(
id int identity(1,1),
age int,
name varchar(255)
)
INSERT INTO #Student S
VALUES(21,'bob'),
(21,'tom'),
(21,'dick'),
(21,'william'),
(35,'mark'),
(35,'anthony')
SELECT age,COUNT(*),STUFF(
(
SELECT ',' + name
FROM #Student SS
WHERE SS.age = S.age
FOR XML PATH('')
), 1, 1, '')
FROM #Student s
GROUP BY age

faster way to do this select query

Say Employee has three columns
FirstName, LastName and ID.
The query should first search for a name in firstname, only if its not found search for last name.
so select *from Employee where FirstName = 'test%' or lastname='test'%'. wont' work.
The query below will work.
select FirstName, LastName, ID
from EMPLOYEE
WHERE
LastName = 'Test%'
AND
(COUNT(SELECT FirstName, LastName, ID FROM EMPLOYEE WHERE FirstName = 'Test%')=0)
OR
SELECT FirstName, LastName, ID FROM EMPLOYEE WHERE FirstName = 'Test%'
I need to map this back to NHibernate, is there a faster efficient way of doing this instead of making two database calls?
Give this one a try:
SELECT FirstName, LastName, ID FROM EMPLOYEE WHERE FirstName = 'Test%'
OR (FirstName <> 'Test%' AND LastName = 'Test%')
FROM Employee
WHERE (FirstName LIKE 'Test%' AND LastName NOT LIKE 'Test%')
OR (LastName LIKE 'Test%' AND firstName NOT LIKE 'Test%')
Granted you don't care what order they come back in. If the records must come back with the records that the first name matches, followed by the names where the last name match, then this won't work.
"Premature optimization is the root of all evil".
Why would you care of how the search is done as the optimizer sees it, instead of declaring what you want?
It all boils down to a boolean truth table: when FirstName matches, you want the record (whatever is in LastName, match or nomatch) and if FirstName does not match, you want the record when LastName matches:
F match, L match => yes
F match, L nomatch => yes
F nomatch, L match => yes
F nomatch, L nomatch => no
That is exactly the OR condition: (FirstName matching) OR (LastName matching); the only discarded records are when both FirstName and LastName do not match.
The boolean optimization will ensure that the 2nd condition is not even evaluated when the 1st one is true.
So your query is:
SELECT FirstName, LastName, ID
FROM Employee
WHERE (FirstName LIKE 'Test%')
OR (LastName LIKE 'Test%')
UPDATE: I may have misunderstood the goal if it is indeed not to return any LastName match if records were found with only the FirstName...
Anyway, the stance on premature optimization is still valid...
You need somehow a 2 pass query as you cannot tell if LastName is to be considered until you're sure you don't have any match on FirstName. But with proper indexes and statistics, the optimizer will make it very efficient.
The query:
SELECT FirstName, LastName, ID
FROM Employee
WHERE (FirstName LIKE 'Test%')
OR (LastName LIKE 'Test%'
AND (SELECT Count(ID)
FROM Employee
WHERE FirstName LIKE 'Test%') = 0)
is only marginally more expensive than the previous.
Select *
From Employee
Where FirstName Like #Text + '%'
Union
Select *
From Employee
Where LastName Like #Text + '%';
I don't think any of these queries answers the question. My understanding is that a search on 'John%' should return employees with last name John, Johnson, etc. ONLY if there were no employees with first name John, Johnny, etc. All the queries show will return both John Adams and Lyndon Johnson if the table contains both, but only John Adams should appear, because last names should be matched ONLY if there are no first names that matched.
Here's a proposal using SQL Server syntax. It should be possible to write this in other dialects of SQL:
select top (1) with ties
FirstName, LastName, ID
from (
select
0 as SearchLastNames,
FirstName, LastName, ID
from EMPLOYEE
where FirstName like 'Test%'
union all
select
1 as SearchLastNames,
FirstName, LastName, ID
from EMPLOYEE
where LastName like 'Test%'
) as T
order by SearchLastNames;
If there are any matching first names, the smallest SearchLastNames value will be 0, and the TOP (1) with ties .. order by SearchLastNames will return information only for the first name matches (where SearchLastNames is 0).
If there are no matching first names, the only SearchLastNames value will be 1. In that case, TOP will return information for all last name matches (where SearchLastNames is 1), if there are any.
A more clumsy, but more portable solution is this:
select
FirstName, LastName, ID
from EMPLOYEE
where FirstName like 'Test%'
union all
select
FirstName, LastName, ID
from EMPLOYEE
where LastName like 'Test%'
and not exists (
select
FirstName, LastName, ID
from EMPLOYEE
where FirstName like 'Test%'
);