How to select a value with a column name that also needs selected? - sql

The SQL Server 2005 table I'm working from is really strange. Here's a simplified example:
TABLE 1:
key | a | b | c | d | e | f
z 0 1 2 3 4 5 6
y 1 8 9 10 11 12 13
x 14 15 16 17 18 19 20
w 21 22 23 24 25 26 27
TABLE 2:
id | Value
1 a
2 b
3 c
4 e
5 f
What I need to accomplish is to, in a single statement, select the column name from a different table, then get the value here. So it would be something like "Select (select colName from table2 where id=VAR1) From table1 where key = VAR2"
So table2 will return either a/b/c/d/e/f, and then the main statement will get the value of the corresponding value based on the key.
Table2 will always return a-f, and I will know the VAR1 and VAR2 ahead of time.

You can use UNPIVOT:
SELECT [key], val, col
FROM
(SELECT [key], a, b, c, d, e, f
FROM table1
WHERE [key] = #var2) AS src
UNPIVOT
(val FOR col IN
(a, b, c, d, e, f)
)AS unpvt
WHERE col = (SELECT value FROM table2 WHERE id = #var1)
UNPIVOT operation transposes table data from columns to rows creating an extra field where column name is placed. This way you can query table data using the name of the column that is obtained from table2.
Demo here

Related

To pull 1 record out of multiple records having same data in a field based on other fields

A | B | C | D | E
a y 6 12 21
b n 3 10 5
c n 4 12 12
c n 7 12 2
c y 1 12 22
d n 6 10 32
d n 7 10 32
OUTPUT TABLE:
A | B | C | F
a y 6 21
b n 3 12
c y 1 22
d n 6 10
I have a table that contains certain fields. From that table I want to remove duplicate records in A and produce the output table.
Now, the field F is calculated based on the field C when there are no duplicates for the records in A. So, if there is only one record of a in A then if C>5 then the F Column(Output table) pulls the record in E column. So, if record b has the value <5 in field C, then the F column (output table) will pull the record in D column for b. I have been able to achieve this using a case statement.
However, when there are duplicate records in column A, I want only one of the records based on the column B. Only that record should be pulled that has the value 'y' in column B and where the column F contains the value from column E. If none of the duplicate records in A have a value of 'n' in the B column, then pull any record with column D as column F in the output table. I am not able to figure out this part.
Please let me know if anything is not clear.
Code I am using:
SELECT A,B,C,
CASE
WHEN (SELECT COUNT(*) FROM MyTable t2 WHERE t1.A=t2.A)>1
THEN (SELECT TOP 1 CASE WHEN b='y' THEN E ELSE D END
FROM MyTable t3
WHERE t3.A=t1.A
ORDER BY CASE WHEN b='y' THEN 0 ELSE 1 END)
ELSE {
case when cast(C as float) >= 5.00 then (Case when E = '0.00' then D else E end)
when cast(C as float)< 5.00 then D end )
}
END AS F
FROM MyTable t1
You might want to encapsulate this logic in a Function to make it look cleaner, but the logic would go like this:
IF the record count of rows in the table with the same value for A as the current row is greater than 1, THEN SELECT the TOP 1 record with this value for A ORDER BY CASE WHEN b='y' THEN 0 ELSE 1 END
Use another CASE WHEN b='y' to determine if you will use column E or D for output column F.
And ELSE (the record count is not greater than 1), use your existing CASE expression.
EDIT: Here is a more psuedo-codey explanation:
WITH cte AS (SELECT A,B,C,
ROW_NUMBER() OVER (PARTITION BY A, ORDER BY CASE WHEN b='y' THEN 0 ELSE 1 END) rn
FROM MyTable
)
SELECT A,B,C,
CASE
WHEN (SELECT COUNT(*) FROM MyTable t2 WHERE t1.A=t2.A)>1
THEN CASE WHEN b='y' THEN E ELSE D END
ELSE {use your existing CASE Expression}
END AS F
FROM cte t1
WHERE rn=1

How to add two values of the same column in a table

Consider the following table?
ID COL VALUE
1 A 10
2 B 10
3 C 10
4 D 10
5 E 10
Output:
ID COL VALUE
1 A 10
2 B 20
3 C 30
4 D 40
5 E 50
Based on your (deleted) comment in output it is taking up the sum of the upper values, it sounds like you're wanting a cumulative SUM().
You can do this with a windowed function:
Select Id, Col, Sum(Value) Over (Order By Id) As Value
From YourTable
Output
Id Col Value
1 A 10
2 B 20
3 C 30
4 D 40
5 E 50
Please make use of the the below code to obtain the cumulative sum. The code is working as expected with SQL Server 2012.
DECLARE #Table TABLE (ID int, COL CHAR(2), VALUE int)
INSERT #Table
(ID,COL,[VALUE])
VALUES
(1,'A',10),
(2,'B',10),
(3,'C',10),
(4,'D',10),
(5,'E',10)
SELECT t.ID,t.COL,SUM(VALUE) OVER (ORDER BY t.ID) AS VALUE
FROM #Table t
Not really sure what you are asking for. If my assumption is correct, you want to SUM the contents of a column and group it.
Select sum(value), col
from table
group by col

SQL select combine data from multiple rows into a single row

I have a table that looks similar to this:
ID OLD NEW TIME
1 a b 5
1 b c 7
1 c d 45
1 d e 4
2 a b 1
2 b d 8
2 d e 45
3 b c 15
3 c d 14
And I would like to build a report that looks like this (basically for each OLD data point grab the TIME value):
ID TimeForA TimeForB TimeForC TimeForD
1 5 7 45 4
2 1 8 NULL 45
3 NULL 15 14 NULL
I have been able to get all the data into the correct columns, but have not been able to combine each row into a single row for each ID. My current query looks like this (no I don't have every column in place yet, still just testing):
WITH CTE (id, ATime, BTime)
AS
(
select T1.oid, T1.loggedFor, null, T1.time as Atime
from Table1 T1
where T1.OLD = 'a'
union
select T1.oid, T1.loggedFor, T1.time as BTime, null
from Table1 T1
where T1.old = 'b'
)
select ID, ATime, BTime
from CTE
order by ID
Any help appreciated!
Try this:
select id,
sum(if(old = 'a',time,null)) as time_for_a,
sum(if(old = 'b',time,null)) as time_for_b,
sum(if(old = 'c',time,null)) as time_for_c,
sum(if(old = 'd',time,null)) as time_for_d
from test_tbl
group by id
order by id;

Keeping track of auto increment columns in a cursor

I wrote a cursor where I needed to copy some rows and insert it into a table with only 1 column different. Say for example I have a table A like this
Id | CID | Country
1 X A
2 X B
3 X C
'Id' in this table is auto increment and primary key and Country is the countries visited by that CID. So when I was asked to update the table where every country visited by CID 'X' has also been visited by CID 'Y'. I wrote a cursor and did an insert into with CID 'Y' and the Country. After I executed my cursor, table A became this:
Id | CID | Country
1 X A
2 X B
3 X C
4 Y A
5 Y B
6 Y C
Now there is another table B that is as follows, where AId is the foreign key referencing Id in A.
AId | AgeOfKids
1 20
1 23
1 28
2 21
2 24
2 29
3 22
3 25
I want to be able to add rows to this table such that it becomes:
AId | AgeOfKids
1 20
1 23
1 28
2 21
2 24
2 29
3 22
3 25
4 20
4 23
4 28
5 21
5 24
5 29
6 22
6 25
To explain in words, the AIds that have the same countries in table A must have the same BeIds in table B. Is it possible to accomplish this? Is so, how can I accomplish this?
Use the OUTPUT clause:
declare #t table (Id int not null,Country char(1) not null)
insert into TableA (CID,Country)
output inserted.id,inserted.Country into #t
select 'Y',Country from TableA where CID = 'X'
And then (should be part of the same batch as the above):
insert into TableB (AId,AgeOfKids)
select t.ID,b.AgeOfKids
from #t t
inner join
TableA a
on
t.Country = a.Country and
a.CID = 'X'
inner join
TableB b
on
a.ID = b.AId
To populate table B.

SQL replace value in a field in a row if it exists, else create a row and populate that value

My request is a little strange and specific, please bear with me.
I have an Access 2003 database with a Comments table that has several hundred thousand lines in it. There are several fields - let's call them A, B, C, D and comment. Columns A-C form the PK of the table. Thus, you could have 5, 10, or 50 rows which have different comments, but all pertain to the A-C PK.
I have another table called CORE which contains a table core that has fields A, B, C, D (A-C PK) and comment_value_insert.
What I want to do:
In Comments, for each "set" of identical A-C rows (Field D can differ), if none of their comment values matches a certain value (let's call it critical), then look up the same row in CORE and insert into the comments table a new row with A-D and Comments.comment = core.comment_value_insert.
I'm not even sure if this is possible with SQL (perhaps VBA? Hence the tag). Any advice anyone?
For further clarification please ask away.
Huge thanks in advance.
EDIT
To demonstrate exactly what I want:
If my Comments table looks like
A | B | C | D | Comment
1 2 3 b val1
1 2 3 x val2
1 2 3 a val3
2 9 8 z val4
2 9 8 a val5
3 3 3 x val6
END
And my CORE Table looks like
A | B | C | D | Comment_value_insert
1 2 3 u critical1
2 9 8 t critical2
4 8 6 x critical3
END
Then I'd want the critical1 row from CORE to be inserted into Comments, as well as the critical2 row, but not the critical3 row.
Then the final product in the Comments table will be
A | B | C | D | Comment
1 2 3 b val1
1 2 3 x val2
1 2 3 a val3
1 2 3 u critical1
2 9 8 z val4
2 9 8 a val5
2 9 8 t critical2
3 3 3 x val6
END
Try something like this for the INSERT part. For the UPDATE part you should provide more information.
-- EDIT --
INSERT INTO Comments ( A, B, C, D, Comment )
SELECT DISTINCT C.A, C.B, C.C, C.D, C.comment_value_insert
FROM Core AS C INNER JOIN Comments as C1 ON C.A = C1.A and C.B = C1.B and C.C = C1.C
WHERE NOT EXISTS (SELECT * FROM Comments AS O WHERE O.Comment = "Critical" AND O.A = C.A AND O.B = C.B AND O.C = C.C);
Regards,
** This version worked for me **
INSERT INTO comments
SELECT a,
b,
c,
d,
comment_value_insert AS comment
FROM core
WHERE EXISTS (SELECT comments.*
FROM comments
WHERE core.c = comments.c
AND core.b = comments.b
AND core.a = comments.a)
AND NOT EXISTS (SELECT comments.*
FROM comments
WHERE core.c = comments.c
AND core.b = comments.b
AND core.a = comments.a
AND core.comment_value_insert = comments.comment)