I have a table containing numbers of people in each area, by age.
There is a column for each age, as shown in this table (junk data):
Area
0
1
2
3
...
90+
A
123
65
45
20
--
66
B
442
456
124
422
--
999
C
442
99
88
747
--
234
I need to group these figures into age bands (0-19. 20-39, 40-59...)
eg:
Area
0-19
20-39
40-59
60+
A
789
689
544
1024
B
1564
884
1668
1589
C
800
456
456
951
What is the best way to do this?
I could do a simple SUM as below, but that feels like a massive amount of script for something that feels like it should be straightforward.
SELECT
[0]+[1]+[2]+...[19] AS [0-19],
[20]+[21]+[22]+...[39] AS [20-39]
...
Is there a simpler way? I'm wondering if PIVOT can help but am struggling to visualise how to use it to get my desired result.
Hoping I'm missing something obvious!
EDIT This is how the data has been supplied to me, I know it's not a great table design but unfortunately that's out of my hands.
I would suggest creating a view on top of your table like so:
CREATE VIEW v_t_normal
SELECT Area, Age, Value
FROM t
CROSS APPLY (VALUES
(0, [0])
(1, [1])
...
(90, [90+])
) AS ca(Age, Value)
That view will normalize present your data in somewhat normalized form. You will not be able to edit the data in the view but you should be able to perform basic math and aggregation on the data. The 90+ value will still cause headache as it encapsulates more than one value.
I'm going to answer by suggesting an alternative table design which will make life easier:
Area | Age | Count
A | 0 | 123
A | 1 | 65
...
B | 0 | 442
Here we are storing each area's age in a separate record, rather than column. With this design in place, your ask is easy to come by using conditional aggregation:
SELECT
Area,
SUM(CASE WHEN Age BETWEEN 0 AND 19 THEN Count ELSE 0 END) AS [0-19],
SUM(CASE WHEN Age BETWEEN 20 AND 39 THEN Count ELSE 0 END) AS [20-39],
...
FROM yourNewTable
GROUP BY Area;
Related
We have a table Property in our database containing a counter in every row stored in the NextVoucherNumber integer column. There are about 2000 rows there.
ID ... {other columns} ... NextVoucherNumber
-----------------------------------------------
1 112
2 34
3 29
4 9456
.... ....
2000 233
We have an issue with a concurrent access to the table.
To improve the performance we would like to extract those columns to a separate table PropertyVoucherNumbers with a 1:1 relation between the rows.
ID NextVoucherNumber
------------------------
1 112
2 34
3 29
4 9456
.... ....
2000 233
Alternatively, we could maintain sequences for every row.
Seq_VoucherNumber_1, Seq_VoucherNumber_2, ... Seq_VoucherNumber_2000.
Looks like the same triggers just a little dynamic SQL there.
Could you please describe what the problems we will face using the second solution?
Can you suggest any better solution?
I would like to create a script that takes the rows of a table which have a specific mathematical difference in their ASCII sum and to add the rows to a separate table, or even to flag a different field when they have that difference.
For instance, I am looking to find when the ASCII sum of word A and the ASCII sum of word B, both stored in rows of a table, have a difference of 63 or 31.
I could probably use a loop to select these rows, but SQL is not my greatest virtue.
ItemID | asciiSum |ProperDiff
-------|----------|----------
1 | 100 |
2 | 37 |
3 | 69 |
4 | 23 |
5 | 6 |
6 | 38 |
After running the code, the field ProperDiff will be updated to contain 'yes' for ItemID 1,2,3,5,6, since the AsciiSum for 1 and 2 (100-37) = 63 etc.
This will not be fast, but I think it does what you want:
update t
set ProperDiff = 'yes'
where exists (select 1
from t t2
where abs(t2.AsciiSum - t.AsciiSum) in (63, 31)
);
It should work okay on small tables.
I am looking to make a very simple report to condense and show data side by side. All of the examples of reports I find are only row by row.
The query I will use will only have three schema "Company, Model, Total"
The format I am trying to get to is
Company Model Total Company Model Total
A 123 2 B 123 4
A 222 3 B 333 3
A 444 7 B 444 7
The idea is to present the information in a way that multiple companies side by side can compare inventory of the same model and find discrepencies. Ideally the report would eventually group all Model's that span every company at the top, but thats a next generation problem.
I have attempted conditional formating on multiple "Company" boxes, but the conditionals do not seem to be applying properly or for some reason every "Company" box is adopting the same conditionals.
I think you want a crosstab query grouping by model (the rowHeader), company as the column header, and first(total) as the value.
The results should look like
model A total B total
123 2 4
222 3
333 3
444 7 7
then you can create another query based on the crosstab results to calculate the difference between company totals, if you want.
You have to do this in two steps:
Build a query that gives you:
Company Model Total
A 123 2
A 222 3
A 444 7
B 123 4
B 333 3
B 444 7
Let's call q this query.
Build a second query
SELECT q1.Company, q1.Model, q1.Total, q1.Company, q2.Model, q2.Total
FROM q AS q1 INNER JOIN q AS q2 ON q1.Model = q2.Model
WHERE q1.company < q2.company;
This will give you:
A 123 2 B 123 4
A 444 7 B 444 7
(There are no matching data for models 222 and 333)
I am new to SQL Server and need help with one of my SQL query.
I have 2 tables (Rating and LikeDislike).
I am trying to get data from both of these tables using a LEFT JOIN like this:
SELECT distinct LD.TopicID, R.ID, R.Topic, R.CountLikes, R.CountDisLikes, LD.UserName, LD.Clikes
FROM Rating As R
LEFT JOIN LikeDislike AS LD on LD.TopicID = R.ID
The above SELECT statement displays results fine but also includes duplicates. I want to remove duplicates when the data is displayed, I tried using DISTINCT and GROUP BY, but with no luck, maybe because I am not using it correctly.
To be more clear and less confusing let me tell you what exactly each table does and what I am trying to achieve.
The Rating table has following columns (ID, Topic, CountLikes, CountDisLikes, Extra, CreatedByUser). It stores topic information and number of likes and dislikes for each topics and the UserID of the user who created that topic.
Rating table with sample data
ID Topic CountLikes CountDisLikes Extra CreatedByUser
1 Do You Like This 211 58 YesId 2
2 Or This 17 25 This also 3
79 Testing at home 1 0 Testing at home 2
80 Testing at home again 1 0 Testing 2
82 testing dislikes 0 1 Testing 2
76 Testing part 3 7 5 Testing 3 4
77 Testing part 4 16 6 Testing 4 5
The LikeDisLike table has following columns (ID, TopicID, UserName, Clikes). TopicID is a FK to the ID column in Rating table.
LikeDislike table with sample data
ID TopicID UserName Clikes
213 77 2 TRUE
214 76 2 FALSE
215 77 5 TRUE
194 77 3 TRUE
195 76 3 FALSE
196 2 3 TRUE
197 1 3 FALSE
Now what I am trying to do is get information from both of this table without duplicate rows. I need to get data all the columns from Rating table + UserName and Clikes columns from LikeDislike table without any duplicate rows
Below are the results with duplicates
TopicID ID Topic CountLikes CountDislikes UserName Clikes
NULL 79 Testing at home 1 0 NULL NULL
NULL 80 Testing at home2 1 0 NULL NULL
NULL 82 testing dislikes 0 1 NULL NULL
1 1 Do You Like This 211 58 3 FALSE
2 2 Or This 17 25 3 TRUE
76 76 Testing part 3 7 5 2 FALSE
76 76 Testing part 3 7 5 3 FALSE
77 77 Testing part 4 16 6 2 TRUE
77 77 Testing part 4 16 6 3 TRUE
77 77 Testing part 4 16 6 5 TRUE
Just like in yesterday's post, I don't think you understand what DISTINCT is suppose to return you. Because you have different values in your LikeDislike table, you are returning the DISTINCT rows.
Let's take TopicId 77 for instance. It returns 3 DISTINCT rows because you have 3 matching records in your LikeDislike table. If your desired output is a single row where the UserName and Clikes are comma delimted, that is possible -- look into using for xml and perhaps stuff (here is a recent answer on the subject). Or if you want to return the first row that matches the TopicId, then that is possible as well -- look into using a subquery with row_number.
Please let us know your desired output and we can help provide a solution.
Good luck.
I am trying to count the number of times a value (mytype) appears within a distinct id value, and update my table with this count (idsubtotal) for each row. The table I have:
id | mytype | idsubtotal
-----+--------+-----------
44 red
101 red
101 red
101 blue
101 yellow
494 red
494 blue
494 blue
494 yellow
494 yellow
I need to calculate/update the idsubtotal column, so it is like:
id | mytype | idsubtotal
-----+--------+-----------
44 red 1
101 red 2
101 red 2
101 blue 1
101 yellow 1
494 red 1
494 blue 2
494 blue 2
494 yellow 2
494 yellow 2
When I try this below, it is counting how many times the mytype value appears in the entire table, but I need to know how many times it appears within that sub-group of id values (e.g. How many times does "red" appear within id 101 rows, answer = 2).
SELECT id, mytype,
COUNT(*) OVER (PARTITION BY mytype) idsubtotal
FROM table_name
I know storing this subtotal in the table itself (versus calculating it live when needed) constitutes a bad data model for the table, but I need to do it this way in my case.
Also, my question is similar to this question but slightly different, and nothing I've tried to tweak using my very primitive understanding of SQL from the previous responses or other posts have worked. TIA for any ideas.
UPDATE table_name a
SET idsubtotal=( SELECT COUNT(1)
FROM table_name b
WHERE a.id=b.id
AND a.mytype=b.mytype
)
When I try this below, it is counting how many times the mytype value appears in the entire table, but I need to know how many times it appears within that sub-group of id values (e.g. How many times does "red" appear within id 101 rows, answer = 2).
SELECT id, mytype, COUNT(*)
FROM table_name
GROUP BY id, mytype