I'm looking for a sql instruction (Select) to create a table format from a existing table.
I have a table in this format.
Id|Record|Title |Value|
1. |1 |name |John |
2. |1 |ammount|200 |
3. |2 |name |Lisa |
4. |2 |ammount|400 |
However I need to show information in this format
Record|Name|Ammount|
1. |John| 200|
2. |Lisa| 400|
I don't want to create a new table, I'm looking for a select or join operation.
Do you know any instruction to perform this operation?
Thanks in advance.
SELECT record,
MAX(CASE WHEN Title = 'name' THEN Value END) AS Name,
MAX(CASE WHEN Title = 'ammount' THEN Value END) AS Ammount
FROM YourTable
GROUP BY record
SQLFIDDLE
You can try this (assuming it's MySQL):
SELECT
A.Record,
A.Value AS Name,
B.Value AS Ammount
FROM
tbl A
JOIN
tbl B
ON
A.Record = B.Record
WHERE
A.Title = 'name' AND
B.Title = 'ammount'
Basically you join the same table twice through Record value, filter the results by Title column and select required columns.
SQLfiddle example
SELECT tt.record,
(SELECT value FROM t WHERE tt.record = record AND title = 'name') AS name,
(SELECT value FROM t WHERE tt.record = record AND title = 'ammount') AS ammount
FROM t as tt
GROUP BY tt.record
;
Related
TABLE A: Pre-joined table - Holds a list of providers who belong to a group and the group the provider belongs to. Columns are something like this:
ProviderID (PK, FK) | ProviderName | GroupID | GroupName
1234 | LocalDoctor | 987 | LocalDoctorsUnited
5678 | Physican82 | 987 | LocalDoctorsUnited
9012 | Dentist13 | 153 | DentistryToday
0506 | EyeSpecial | 759 | OphtaSpecialist
TABLE B: Another pre-joined table, holds a list of providers and their demographic information. Columns as such:
ProviderID (PK,FK) | ProviderName | G_or_I | OtherColumnsThatArentInUse
1234 | LocalDoctor | G | Etc.
5678 | Physican82 | G | Etc.
9012 | Dentist13 | I | Etc.
0506 | EyeSpecial | I | Etc.
The expected result is something like this:
ProviderID | ProviderName | ProviderStatus | GroupCount
1234 | LocalDoctor | Group | 2
5678 | Physican82 | Group | 2
9012 | Dentist13 | Individual | N/A
0506 | EyeSpecial | Individual | N/A
The goal is to determine whether or not a provider belongs to a group or operates individually, by the G_or_I column. If the provider belongs to a group, I need to include an additional column that provides the count of total providers in that group.
The Group/Individual portion is relatively easy - I've done something like this:
SELECT DISTINCT
A.ProviderID,
A.ProviderName,
CASE
WHEN B.G_or_I = 'G'
THEN 'Group'
WHEN B.G_or_I = 'I'
THEN 'Individual' END AS ProviderStatus
FROM
TableA A
LEFT OUTER JOIN TableB B
ON A.ProviderID = B.ProviderID;
So far so good, this returns the expected results based on the G_or_I flag.
However, I can't seem to wrap my head around how to complete the COUNT portion. I feel like I may be overthinking it, and stuck in a loop of errors. Some things I've tried:
Add a second CASE STATEMENT:
CASE
WHEN B.G_or_I = 'G'
THEN (
SELECT CountedGroups
FROM (
SELECT ProviderID, count(GroupID) AS CountedGroups
FROM TableA
WHERE A.ProviderID = B.ProviderID
GROUP BY ProviderID --originally had this as ORDER BY, but that was a mis-type on my part
)
)
ELSE 'N/A' END
This returns an error stating that a single row sub-query is returning more than one row. If I limit the number of rows returned to 1, the CountedGroups column returns 1 for every row. This makes me think that its not performing the count function as I expect it to.
I've also tried including a direct count of TableA as a factored sub-query:
WITH CountedGroups AS
( SELECT Provider ID, count(GroupID) As GroupSum
FROM TableA
GROUP BY ProviderID --originally had this as ORDER BY, but that was a mis-type on my part
) --This as a standalone query works just fine
SELECT DISTINCT
A.ProviderID,
A.ProviderName,
CASE
WHEN B.G_or_I = 'G'
THEN 'Group'
WHEN B.G_or_I = 'I'
THEN 'Individual' END AS ProviderStatus,
CASE
WHEN B.G_or_I = 'G'
THEN GroupSum
ELSE 'N/A' END
FROM
CountedGroups CG
JOIN TableA A
ON CG.ProviderID = A.ProviderID
LEFT OUTER JOIN TableB
ON A.ProviderID = B.ProviderID
This returns either null or completely incorrect column values
Other attempts have been a number of variations of this, with a mix of bad results or Oracle errors. As I mentioned above, I'm probably way overthinking it and the solution could be rather simple. Apologies if the information is confusing or I've not provided enough detail. The real tables have a lot of private medical information, and I tried to translate the essence of the issue as best I could.
Thank you.
You can use the CASE..WHEN and analytical function COUNT as follows:
SELECT
A.PROVIDERID,
A.PROVIDERNAME,
CASE
WHEN B.G_OR_I = 'G' THEN 'Group'
ELSE 'Individual'
END AS PROVIDERSTATUS,
CASE
WHEN B.G_OR_I = 'G' THEN TO_CHAR(COUNT(1) OVER(
PARTITION BY A.GROUPID
))
ELSE 'N/A'
END AS GROUPCOUNT
FROM
TABLE_A A
JOIN TABLE_B B ON A.PROVIDERID = B.PROVIDERID;
TO_CHAR is needed on COUNT as output expression must be of the same data type in CASE..WHEN
Your problem seems to be that you are missing a column. You need to add group name, otherwise you won't be able to differentiate rows for the same practitioner who works under multiple business entities (groups). This is probably why you have a DISTINCT on your query. Things looked like duplicates which weren't. Once you've done that, just use an analytic function to figure out the rest:
SELECT ta.providerid,
ta.providername,
DECODE(tb.g_or_i, 'G', 'Group', 'I', 'Individual') AS ProviderStatus,
ta.group_name,
CASE
WHEN tb.g_or_i = 'G' THEN COUNT(DISTINCT ta.provider_id) OVER (PARTITION BY ta.group_id)
ELSE 'N/A'
END AS GROUP_COUNT
FROM table_a ta
INNER JOIN table_b tb ON ta.providerid = tb.providerid
Is it possible that your LEFT JOIN was going the wrong direction? It makes more sense that your base demographic table would have all practitioners in it and then the Group table might be missing some records. For instance if the solo prac was operating under their own SSN and Type I NPI without applying for a separate Type II NPI or TIN.
I need to make a query that will pull records based on multiple maximum values in a group in a specific hierarchy. I have a table that looks like this:
Key Classificaiton set_ind Date Rank Amount
1 1 1 5/2/2017 1 15
2 1 1 5/2/2017 3 2
3 1 0 4/2/2017 2 32
4 2 1 5/1/2017 2 5
5 2 1 1/5/2017 4 16
6 2 1 12/13/2016 1 12
7 2 0 12/13/2016 3 20
8 3 1 4/5/2017 2 15
9 3 0 4/8/2017 1 23
I need to be able to get the Key for every record that has a set_ind = 1, the most recent date, and the highest rank, in that order of hierarchy for each classification.
So from the sample table, the query would pull the record corresponding to key 2, 4 and 8.
I've tried using this code:
proc sql;
create table test as
select key, classification, max(date), max(rank)
from ods.data
where set_ind = 1
group by 2, 1;
quit;
I know I'm still getting dups in the classification because I have the key in the query, but I need the key to be able to identify the specific record.
I've also tried running two queries, one to find max(date) and then doing a right join on another query to find max(rank) but that hasn't worked either.
For both queries the data I need will have no dups in the Classification column and will have a key to go with each record. When I run the code above, I get dups. I'm not sure how to pull the data correctly.
Since you are using SAS. Giving you a efficient way of doing the problem in data step.
Step1: Sort the data by classification,date,rank
Step2: Pick last record of each classification by first. so as to obtain the max dates against each classification. Incase the dates are same then picking the max of rank.
proc sort data =abc;
by Classificaton Date rank;
run;
data abc1;
set abc(where=(set_ind=1));
by Classificaton Date rank;
if last.Classificaton ;
drop amount set_ind;
run;
My Output:
|Key |Classificaton |Date |Rank
|2 |1 |5/2/2017 |3
|4 |2 |5/1/2017 |2
|8 |3 |4/5/2017 |2
Let me know in case of any queries.
Subqueries like this leave me hesitant to post this answer, but it'll work for you. I'm really interested in seeing a better answer, though!
select *
from ods.data
where set_ind = 1
and date = (select max(Date) from ods.data where set_ind=1)
and rank = (select max(Rank) from ods.data where set_ind=1 and date=(select max(Date) from ods.data where set_ind=1))
Edit: I had a brain fart, and copied and pasted my test query, without replacing it with your table's schema. I've corrected the query with the appropriate table/column names.
I found a way to solve this problem using proc sql, even though a better solution for SAS has been presented.
I first created a table that pulls the max values for date and rank, but has duplicate classifications:
proc sql;
create table max_info as
select classification
,max(date) as date
,max(rank) as rank
from ods.data
where set_ind = 1
group by 1;
quit;
I then go to the original table and find the records that match the classification, max date and max rank with this code:
proc sql;
create table max as
select *
from ods.data a
right join work.max_info b on a.classification = b.classification and
a.date = b.date and
a.rank = b.rank
where set_ind = 1;
quit;
No database type mentioned.
In Vertica (and I think Postgres, too), you can do it like below.
They support the LIMIT clause with OLAP window expression:
WITH
-- input as from question, don't use in real query ...
input(Key,classification,set_ind,Date,Rank,Amount) AS (
SELECT 1,1,1,DATE '5/2/2017' ,1,15
UNION ALL SELECT 2,1,1,DATE '5/2/2017' ,3,2
UNION ALL SELECT 3,1,0,DATE '4/2/2017' ,2,32
UNION ALL SELECT 4,2,1,DATE '5/1/2017' ,2,5
UNION ALL SELECT 5,2,1,DATE '1/5/2017' ,4,16
UNION ALL SELECT 6,2,1,DATE '12/13/2016',1,12
UNION ALL SELECT 7,2,0,DATE '12/13/2016',3,20
UNION ALL SELECT 8,3,1,DATE '4/5/2017' ,2,15
UNION ALL SELECT 9,3,0,DATE '4/8/2017' ,1,23
)
-- end of input, real query starts here
SELECT
*
FROM input
WHERE set_ind=1
LIMIT 1 OVER(PARTITION BY classification ORDER BY date DESC, rank DESC)
;
Key|classification|set_ind|Date |Rank|Amount
2| 1| 1|2017-05-02| 3| 2
4| 2| 1|2017-05-01| 2| 5
8| 3| 1|2017-04-05| 2| 15
I'm working on PostgreSQL on a table with this structure :
________________
|project|person|
|_______|______|
|1 |P1 |
|1 |P2 |
|2 |P3 |
|2 |P3 |
|3 |P4 |
|_______|______|
I would like to write a SQL query to select ONLY the rows where one project has more than one person. In other words, I would like to select all the rows where the project is the same but the person is different, excluding the other rows. In my example it would return only the two first rows :
________________
|project|person|
|_______|______|
|1 |P1 |
|1 |P2 |
|_______|______|
I can not wrap my head arround this. Is saw this question which is basically the opposite but I don't see how to make it work for me.
I tried to fiddle with COUNT or HAVING for a long time but I can not grasp the logic of how I should build this query. For example I tried :
SELECT t.person, t.project
FROM table t
GROUP BY r.ide_proj, r.ide_pers
HAVING COUNT(t.person) > 1
but this gives me strange results, including rows whre one projects only has one person, or vice-versa.
Can somebody help me with this little problem ?
Many thanks !
Here's one option using a subquery to get the distinct rows and then a window function to get both the project and the person.
select *
from (
select *, count(person) over (partition by project) cnt
from (select distinct project, person from yourtable) t
) t
where cnt > 1
Or you could use a regular group by query, but you'll need to join the result back to the original table to get the names associated with each project.
select t.*
from yourtable t join (
select project
from yourtable
group by project
having count(distinct person) > 1) t2 on t.project = t2.project
I think the key here is the count(Distinct person) > 1
Select project, person
from table
group by project
having count(distinct person) >1
Trying to pull data from a single table called tblTooling where two TlPartNo numbers are equal to different values and the TlToolNo are not equal for these TlPartNo . This is an Access DB and the following statement gets me close, but still gives too much data.
SELECT DISTINCT
tblTooling.TlToolNo,
tblTooling.TlPartNo,
tblTooling.TlOP,
tblTooling.TlQuantity
FROM tblTooling, tblTooling AS tblTooling_1
WHERE (((tblTooling.TlToolNo)<>tblTooling_1.TlToolNo)
AND ((tblTooling.TlPartNo)="10290722")
AND ((tblTooling_1.TlPartNo)="10295379"));
The included image has the tblTooling structure and Data. Plus the expected results from the query.
You seem to want exclude a ToolNo value when it occurs with both PartNo values. In that case you could group intermediate results by ToolNo, and see whether in such a group there is only one PartNo present (with having). In that case keep that record, and in the outer query, get the two other columns added to it:
SELECT DISTINCT
tblTooling.TlToolNo,
tblTooling.TlPartNo,
tblTooling.TlOP,
tblTooling.TlQuantity
FROM tblTooling
INNER JOIN (
SELECT TlToolNo,
Min(TlPartNo) AS MinTlPartNo,
Max(TlPartNo) AS MaxTlPartNo
FROM tblTooling
WHERE TlPartNo IN ("10290722", "10295379")
GROUP BY TlToolNo
HAVING Min(TlPartNo) = Max(TlPartNo)
) AS grp
ON grp.TlToolNo = tblTooling.TlToolNo
AND grp.MinTlPartNo = tblTooling.TlPartNo
Note that for your sample data this will return 4 rows:
TlToolNo | TlPartNo | TlOP | TlQuantity
----------+----------+------+-----------
T00012362 | 10290722 | OP10 | 2
T00012456 | 10290722 | OP10 | 1
T00013456 | 10290722 | OP20 | 1
T00014348 | 10295379 | OP20 | 1
I think you can do this with not exists:
select t.*
from tblTooling as t
where not exists (select 1
from tblTooling as t2
where t2.TlPartNo in ("10290722", "10295379") and
t2.TlToolNo = t.TlToolNo and
t2.tiid <> t.tiid
) and
t.TlPartNo in ("10290722", "10295379");
This saves on the select distinct, which should be a performance boost.
I preface this by saying I am new to SQL and have been learning on the job thanks to Stack Overflow.
I am running a query from multiple tables (3 in total), and I am trying to get the results for each unique identifier on one row. 1 of the table items has multiple returns, and I am able to write it to where they show as a max command in their own column; however, it still returns multiple rows for the same identifier.
Here's what I have so far:
SELECT tbl.1.field as ID, tbl.2.field as Name, tbl.2.fieldb as Product,
COUNT(*) AS ConfirmedSales
MAX(CASE WHEN tbl.3.field = 'Product1' then 1 else 0 end) as CustomCol1
MAX(CASE WHEN tbl.3.field = 'Product2' then 1 else 0 end) as CustomCol2
FROM tbl.2
LEFT JOIN tbl.2 on tbl.2.x = tbl.1.x
INNER JOIN tbl.3 on tbl.2.x = tbl.3.x
WHERE ((tbl.1.date between '01/01/2014 00:00:00' and 06/30/2014 23:59:59'))
GROUP BY tbl.1.field, tbl.2.field, tbl.2.fieldb
Results return as follows:
Row |ID |Name |CustomCol1 |CustomCol2
1 |8048 |Jon Smith |1 |0
2 |8048 |Jon Smith |0 |1
3 |4044 |Max Williams |0 |0
I would like for the results for CustomCol1 and CustomCol2 to share the same line if the ID is the same. Is this possible?
Consider moving your cases into a subquery like so:
SELECT t.ID, t.name, MAX(s.custom1) AS custom1, MAX(custom2) AS custom2
FROM #tbl1 t
INNER JOIN (SELECT personID
,CASE WHEN s.product = 'product1' THEN 1 ELSE 0 END custom1
,CASE WHEN s.product = 'product2' THEN 1 ELSE 0 END custom2
FROM #sales s) s ON t.ID = s.personID
GROUP BY t.ID, t.Name
This will prevent the duplication you're seeing. If you're ultimate goal is something else, though, give us some more info, and I'm sure someone will have a good answer.