how to unpivot the table, from column to row - sql

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

Related

How to append a default value in a query Row Source Type?

I have a Form that has a Field where the Lookup is set as a Combox Box Display Control, a Table / Query Row Source Type and a Query for the Row Source. I am wondering how to append non-bounded elements to this Combo Box.
Right now, the Combobox looks something like:
Mark
Chris
Mary
Charles
I would like for it to read as:
NONE
Mark
Chris
Mary
Charles
Of course, NONE is not an actual entry in my table. I would just like to append it for redundancy purposes.
My query for the Row Source is:
SELECT StudentId, StudentName FROM Student ORDER BY StudentId
I have tried just appending it like:
SELECT StudentId, StudentName, "NONE" FROM Student ORDER BY StudentId
But it completely skips the NONE part.
So, I am wondering if there's a way to append non-bounded elements to a Combobox that IS properly bound to a result set of a query.
You need union all :
SELECT s.*
FROM ((SELECT NULL AS StudentId, 'NONE' AS StudentName) UNION ALL
(SELECT StudentId, StudentName
FROM Student
)
) s;
You should use UNION in SQL query to join non-existing value
SELECT 0 as StudentId, 'NONE' as StudentName FROM Dual
UNION
SELECT StudentId, StudentName FROM Student
ORDER BY StudentId
Here Dual is table with one row

oracle sql how to match name split through 3 columns?

This database is not mine so i cannot alter it to a single name column (unfortunately).
**table1:**
name1,name2,name3
john,mega,rambo
john,master,travolta
john,super,connor
i'm sending query string $qs to a php file via ajax
file.php?qs=john%rambo
i want it to query the oracle database and return the name "John MEga Rambo", so i thought this would work but it doesn't:
SQL:
SELECT CONCAT(CONCAT(name1,name2),name3) as name
FROM table1
WHERE name LIKE '%{$qs}%'
I guess the biggest problem here is that someone can search by name1 or name2 / name1 or name3. Any ideas ?
Presumably you're getting an invalid identifier error. You can't referance a column alias in the same level of query it's defined (except in order by), because of the order the query is parsed and executed.
You could use a CTE or an inline view (subquery):
SELECT name
FROM (
SELECT CONCAT(CONCAT(name1,name2),name3) as name
FROM table1
)
WHERE name LIKE '%{$qs}%'
With some dummy data:
create table table1 (name1 varchar2(10), name2 varchar2(10), name3 varchar2(10));
insert into table1 (name1, name2, name3) values ('john', 'mega', 'rambo');
insert into table1 (name1, name2, name3) values ('john', 'master', 'travolta');
insert into table1 (name1, name2, name3) values ('john', 'super', 'connor');
that query - with {$qs} replaced with rambo - gets:
NAME
------------------------------
johnmegarambo
As you can see concat won't automatically add whitespace, so you might find the concatenation operator easier:
SELECT name
FROM (
SELECT name1 ||' '|| name2 ||' '|| name3 as name
FROM table1
)
WHERE name LIKE '%{$qs}%'
NAME
--------------------------------
john mega rambo
But if you're looking for more exact matches you might want to check each column instead:
SELECT name1 ||' '|| name2 ||' '|| name3 as name
FROM table1
WHERE name1 = '{$qs}'
OR name2 = '{$qs}'
OR name3 = '{$qs}'
Maybe you want the flexibility to search for partial matches though.
As a further consideration, by default you can only search for values exactly matching the case of the search string - so with your data, searching for RAMBO wouldn't find a match. There are a couple of ways around that if it's an issue for you.
Thank you Alex Poole for the replies, those didn't quite solve the problem BUT it pointed me in the right direction! It seems like oracle is a little bit picky with syntax, so a simple HAVING that would work in MySQL won't work on oracle. I'll post both solutions for ORACLE and MySQL
MySQL:
SELECT CONCAT(CONCAT(name1,name2),name3) AS name
FROM table1
HAVING name LIKE '{%$qs}%'
ORACLE
WITH table1 as ( SELECT CONCAT(CONCAT(name1,name2),name3) as name
FROM table1)
select * from table1 where name like '%{$qs}%'

SQL - Oracle - Duplicate IDs with more than one Customer Name value into a separate column

Please help me determine a "good" or best way of setting up this query, of course, if it will work. = )
Below is an example and basic query that provides CustomerID, Cust Name, UserName and Email. I'm trying to take the multiple username/email fields for one CustID and placing them in a new/separate field so that I have a distinct CustomerID.
An example of the current data is:
Cust_Nbr Cust_Name User_Name Email
0011 Customer11 User1a Email1a
0011 Customer11 User1b Email1b
Trying to achieve:
Cust_Nbr Cust_Name User_Name Email UserName2 Email2
0011 Customer11 User1a Email1a User1b Email1b
The sql is similar to this:
SELECT
cust.CUST_ID,
cust.CUST_NAME,
orders.NAME Orders_Name1,
orders.EMAIL EMAIL1
FROM
CUSTOMER cust,
ORDERS_USERS orders,
SALES_TRANS sls
WHERE
etc...
GROUP BY
etc...
I tried devising a way to do a union copying the select statement 3x and then trying to separate the values with new alias column names, e.g., username1, username2, etc., but that didn't work very well.
Any suggestions? Should I use a count statement with an indicator and then group those as sub selects? Not too sure.
Also, I am familiar with SQL Server format, but please keep in mind this is Oracle sql. Thanks!
It isn't good solution, but if you have known rows you may use:
with tb (Cust_Nbr,Cust_Name,User_Name,Email) as (
select '0011', 'Customer11', 'User1a', 'Email1a' from dual union all
select '0011', 'Customer11', 'User1b', 'Email1b' from dual)
select Cust_Nbr,Cust_Name,
max(decode(user_rn,1,User_Name)) as User1,
max(decode(user_rn,2,User_Name)) as User2,
max(decode(email_rn,1,User_Name)) as Email1,
max(decode(email_rn,2,User_Name)) as Email2
from
(select Cust_Nbr,Cust_Name,User_Name,Email,
row_number() over (partition by Cust_Nbr,Cust_Name order by User_Name) as user_rn,
row_number() over (partition by Cust_Nbr,Cust_Name order by Email) as email_rn
from tb)
group by Cust_Nbr,Cust_Name
first of all i would strongly recommend you to redesign your table(s) and split the data into two tables "customer" and "email" (customer_id, ...) - this will make your life much easier. But if you can't change it here is an answer:
create table customer(id int, name varchar2(100), username varchar2(100), email varchar2(100));
insert into customer
select 1,'Customer11', 'User1a', 'Email1a#mail.com' from dual
union
select 1,'Customer11', 'User1b', 'Email1b#mail.com' from dual
union
select 1,'Customer11', 'User1c', 'Email1c#mail.com' from dual
union
select 2,'Customer12', 'User12a', 'Email12a#mail.com' from dual
;
commit;
select id, name, listagg('<'||username||'> '|| email, ', ') WITHIN GROUP (ORDER BY id)
from customer group by id, name;
Output:
ID NAME USERNAME_EMAIL
1 Customer11 <User1a> Email1a#mail.com, <User1b> Email1b#mail.com, <User1c> Email1c#mail.com
2 Customer12 <User12a> Email12a#mail.com

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"

How to add table column headings to sql select statement

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]