Decomposing a GROUP BY statement - sql

Assuming I have a table SomeTable with the following data:
Primary Key Column1 Column2 Column3 Column4 Column5 Num
1 dat1 abc1 dat3 dat4 por7 1
2 dat1 gcd4 dat3 dat4 yrt8 6
3 dat1 iut7 dat3 dat4 asd6 2
4 other1 other2 other3 other4 other5 4
Another table SomeTableGrouped with a "Group Byed" version created using a query like this:
INSERT INTO SomeTableGrouped
SELECT Column1, Column3, Column4, SUM(Num)
FROM SomeTable
GROUP BY Column1, Column3, Column4
Primary Key Column1 Column3 Column4 Num
100 dat1 dat3 dat4 9
200 other1 other3 other4 4
What I'd like to be able to do is, if I have a primary key of SomeTableGrouped, I need to be able to tell which specific rows from SomeTable it came from.
Example:
In a separate table RandomTable, I have data like this:
Primary Key Column1 SomeTableGroupedId
1 dat1 100
2 dat2 100
If I look at the first row, I need to be able to list out row 1 - 3 from SomeTable
How can I do this? I can't change the schema very much (ie. I can only add new columns, remove columns, add a new table) so a dirty solution is perfectly fine with me.

I think this is what you want.
SELECT id
FROM SomeTable
INNER JOIN SomeTableGrouped ON
(SomeTable.Column1 = SomeTableGrouped.Column1) AND
(SomeTable.Column2 = SomeTableGrouped.Column2) AND
(SomeTable.Column3 = SomeTableGrouped.Column3)
WHERE SomeTableGrouped.id = ...

You don't even need to create all those tables, you only need SomeTable. But here we go...
If you want to find the IDs of the records that summed up, just relate them as they were created:
select st.PrimaryKey as STPK, stg.PrimaryKey as STGPK
from SomeTable st
inner join SomeTableGrouped stg
on (st.Column1 = stg.Column1 and
st.Column3 = stg.Column3 and
st.Column5 = stg.Column5)
However, you should not even have created SomeTableGroupedas a table. It could be a view (look here to see how create views in DB2).
That way, you make sure data is always up-to-date and you don't have to worry about back tracking ("what if Num gets updated?").

Related

How to get unique value from sql table based on charachter length of value

Here I have two columns like below example column1 & column2 in sql table and i want to get unique value row on the basis of column2 column value from table
Below example of dummy table
Column1 Column2
---------- -------------
1001 ab
1001 abc
1001 abcd
2001 wxyz
2001 wxy
2001 wx
In above example value starting from a & another value starting from w in Column2
On the basis of same value character length, i want to get result like below
Output:
Column1 Column2
---------- -----------
1001 abcd
2001 wxyz
Thanks in advance of help :)
If I understood you correctly, you want the highest length (you didn't say what to do when there are two with the same length) but basically you want something like this:
SELECT * FROM YourTable
WHERE (column1,len(column2)) IN(select Column1,max(len(column2))
FROM YourTable
GROUP BY Column1)
If you are looking if your values in column2 are somewhere included in other rows, in other words: If you are looking for rows with combinations of characters which are unique on their own, this might be your solution:
CREATE TABLE TestTable(Column1 INT,Column2 VARCHAR(100));
INSERT INTO TestTable VALUES
(1001,'ab')
,(1001,'abc')
,(1001,'abcd')
,(2001,'wxyz')
,(2001,'xyz')
,(2001,'yz');
SELECT *
FROM TestTable
WHERE NOT EXISTS(SELECT 1
FROM TestTable AS x
WHERE x.Column1=TestTable.Column1
AND LEN(x.Column2)>LEN(TestTable.Column2)
AND x.Column2 LIKE '%' + TestTable.Column2 + '%'
)
DROP TABLE TestTable;

Conditional Join SQL Server

I have a scenario as below:
Source1
Column1
Column2
Source2
Column1
Column2
Output - I need a view;
All the records in Source1 where Column2 is not empty must be in the view.
All the records in Source1 where Column2 is empty must be joined with Source2 (on Column1, the reference between both tables). Wherever it finds a match then Column2 of Source2 should also be included in the view.
Any pointers please..
The easiest way I see is with an union of both queries:
SELECT * FROM Source1 WHERE Column2 IS NOT NULL
UNION
SELECT S2.* FROM Source1 S1
INNER JOIN Source2 S2
ON S1.Column1 = S2.Column1
WHERE S1.Column2 IS NULL
So to recap: only include lines where Source1.Column2 is populated, and include Column2 of Source2 as well if that is also populated?
What you're looking for is a LEFT JOIN. Learn it and love it, because it's one of the handiest things in the whole of SQL.
SELECT s1.Column1, s1.Column2, s2.Column2
FROM source1 s1
LEFT JOIN source2 s2 ON s1.Column1 = s2.Column1
WHERE s1.Column2 IS NOT NULL
Use an outer join between Source1 and Source2.
The specification is a little loose. Did you want the Column2 from Source2 to be returned as a separate (third) column, or did you want the value from that in the second column, replacing the "empty" value of Column2 from Source1?
What are the datatypes of Column2 in Source1 and Source2? Is that character type, numeric, datetime?
How do you define "empty"? For character types, does that include both NULL values and zero length strings?
Also, what is the cardinality of the relationship between the tables, is it one to one, one to many (which way). Is it it mandatory, or possibly one to zero?
Assuming you want all the rows (if there are multiple rows from Source2 that match a row from Source1, and assuming you want a third column, and assuming the datatype of Column2 is character, and assuming "empty" means NULL or zero-length string (that's a whole lot of assumptions)... then something like this:
SELECT s.column1
, s.column2
, IF(IFNULL(s.column2,'')='',t.column2,'') AS t_column2
FROM source1 s
LEFT
JOIN source2 t
ON t.column1 = s.column1
AND IFNULL(s.column2,'') = ''
ORDER BY s.column1, 2, 3
... will return a result that meets the specification. That query can be altered/tweaked to adjust to a tighter (more precise) specification.
EDIT
Ooops.
The example query above was based on yet another assumption: that this was specific to MySQL.
The syntax of the statement above won't "work" in other databases. Here's an equivalent statement, using more ANSI-standards compliant syntax:
SELECT s.column1
, s.column2
, CASE WHEN s.column2 IS NULL OR s.column2 = ''
THEN t.column2
ELSE ''
END AS t_column2
FROM source1 s
LEFT
JOIN source2 t
ON t.column1 = s.column1
AND (s.column2 IS NULL OR s.column2 = '')
ORDER BY s.column1, s.column2
FOLLOWUP
Added an example that demonstrates the behavior:
SQL Fiddle here: http://sqlfiddle.com/#!9/113e6/1
Setup tables and sample rows:
CREATE TABLE source1
( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
, column1 INT
, column2 VARCHAR(8)
);
CREATE TABLE source2
( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
, column1 INT
, column2 VARCHAR(8)
);
INSERT INTO source1 (id, column1, column2) VALUES
(1,NULL,NULL)
,(2,NULL,'foo')
,(3,113,'fee')
,(4,114,'fi')
,(5,115,'')
,(6,116,NULL)
,(7,122,'fo')
,(8,122,'fum')
;
INSERT INTO source2 (id, column1, column2) VALUES
(21,NULL,'doh')
,(22,113,'rey')
,(23,113,'mii')
,(24,114,'fah')
,(25,115,'sew')
,(26,115,'lah')
,(27,116,NULL)
,(28,116,'')
,(29,116,'tea')
,(30,116,'doh')
;
Example query (same as query above):
SELECT s.column1
, s.column2
, IF(IFNULL(s.column2,'')='',t.column2,'') AS t_column2
FROM source1 s
LEFT
JOIN source2 t
ON t.column1 = s.column1
AND IFNULL(s.column2,'') = ''
ORDER BY s.column1, 2, 3
Example query - same as query above PLUS extra id columns
SELECT s.column1
, s.column2
, IF(IFNULL(s.column2,'')='',t.column2,'') AS t_column2
-- ---------------
, s.id AS s_id
, t.id AS t_id
-- ---------------
FROM source1 s
LEFT
JOIN source2 t
ON t.column1 = s.column1
AND IFNULL(s.column2,'') = ''
ORDER BY s.column1, 2, 3
Returns:
column1 column2 t_column2 s_id t_id
------- ------- --------- ------ --------
(NULL) (NULL) (NULL) 1 (NULL)
(NULL) foo 2 (NULL)
113 fee 3 (NULL)
114 fi 4 (NULL)
115 lah 5 26
115 sew 5 25
116 (NULL) (NULL) 6 27
116 (NULL) 6 28
116 (NULL) doh 6 30
116 (NULL) tea 6 29
122 fo 7 (NULL)
122 fum 8 (NULL)
Note that this example includes "duplicate" values in column1, of both source1 and source2, and shows the results that are returned. (The s_id and t_id columns are included to aid in deciphering the rows returned.)

Create duplicates with sql

This might sound a bit confusing at first. But I have a table with data and I want to create duplicates of all the rows in this table. So, if i do:
SELECT *
FROM the_table
it lists all the data in this table. Now, i want to create a copy of all returned results, except for that I want to change data for one column (the date). This will make the new rows unique.
The reason I want to do this is because I want more data in this table since im building statistics out of it for testing purposes. So, if I have this:
**Column1 Column2 Column3**
abc aaa bbb
abcd aaaa bbbb
abcde aaaaa bbbbb
The table will now contain:
**Column1 Column2 Column3**
abc aaa bbb
abcd aaaa bbbb
abcde aaaaa bbbbb
abc aaa bbb_new
abcd aaaa bbbb_new
abcde aaaaa bbbbb_new
insert into your_table
select col1, col2, concat(col3, '_new') from your_table
Consider making a Cartesian Join on your table. This will give you way more data quickly :)
INSERT INTO TABLEDUPLICATES
SELECT * FROM the_table
SELECT * FROM TABLEDUPLICATES UNION
SELECT * FROM the_table
Assuming there is an identity column (ID) you might generate dates (A_Date) like this:
insert into the_table (Column1, Column2, A_Date)
select Column1, Column2, A_Date + (rand(ID) - 0.5) * 100
from the_table
To duplicate rows (all columns) you simply could use
insert into tblname
select * from tblname
to change one column that can be modified to
insert into tblname
select column1, column2, 'fixedvalueforcolumn3' from tblname
But you need a unique value for column 3, so you have to change 'fixedvalueforcolumn3' to a function that will generate some random (unique) value (date in your case) for column 3
insert into tblname
select column1, column2, generateRandomValue() from tblname
Hope that will help you

Querying Same Lookup Table With Multiple Columns

I'm a bit confused on this. I have a data table structured like this:
Table: Data
DataID Val
1 Value 1
2 Value 2
3 Value 3
4 Value 4
Then I have another table structured like this:
Table: Table1
Col1 Col2
1 2
3 4
4 3
2 1
Both columns from Table1 point to the data in the data table. How can I get this data to show in a query? For example, a query to return this:
Query: Query1
Column1 Column2
Value 1 Value 2
Value 3 Value 4
Value 4 Value 3
Value 2 Value 1
I'm familiar enough with SQL to do a join with one column, but lost beyond that. Any help is appreciated. Sample sql or a link to something to read. Thanks!
PS: This is in sqlite
You can join the same table twice:
Select
d1.val As column1,
d2.val As column2
From table1 t
Join data d1 On ( d1.dataId = t.col1 )
Join data d2 On ( d2.dataId = t.col2 )

MySQL get rows but prefer one column value over another

A bit of a strange one, I want to write a MySQL query that will get results from a table, but prefer one value of a column over another, ie
id name value prioirty
1 name1 value1 NULL
2 name1 value1 1
3 name2 value2 NULL
4 name3 value3 NULL
So here name1 has two entries, but one has a prioirty of 1. I want to get all the values from the table, but prefer the values with whatever priorty I'm after.
The results I'd be after would be
id name value prioirty
2 name1 value1 1
3 name2 value2 NULL
4 name3 value3 NULL
An equivalent way of saying it would be 'get all rows from the table, but prefer rows with a priority of x'.
This should do it:
SELECT
T1.id,
T1.name,
T1.value,
T1.priority
FROM
My_Table T1
LEFT OUTER JOIN My_Table T2 ON
T2.name = T1.name AND
T2.priority > COALESCE(T1.priority, -1)
WHERE
T2.id IS NULL
This also allows you to have multiple priority levels with the highest being the one that you want to return (if you had a 1 and 2, the 2 would be returned).
I will also say though that it does seem like there are some design problems in the DB. My approach would have been:
My_Table (id, name)
My_Values (id, priority, value)
with an FK on id to id. PKs on id in My_Table and id, priority in My_Values. Of course, I'd use appropriate table names too.
You need to redesign your table first.
It should be:
YourTable (Id, Name, Value)
YourTablePriority (PriorityId, Priority, Id)
Update:
select * from YourTable a
where a.Id not in
(select b.Id from YourTablePriority b)
This should work in sql server, you may need a little change to make it work in mysql.
Maybe something like:
SELECT id, name, value, priority FROM
table_name GROUP BY name ORDER BY priority
Although not having a database in front of me I can't test it...
If I understand correctly, you want the value of a name given a specific priority, or the value associated with a NULL priority. (You do not necessarily want the MAX(priority) that exists.)
Yes, you've got some awkward design issues which you should address, but let's solve the problem you do have at present (and you can later migrate to the problem you ought to have :) ):
mysql> SET #priority = 1; -- the priority we want, if recorded
mysql> PREPARE stmt FROM "
SELECT
t0.*
FROM
t t0
LEFT JOIN
(SELECT DISTINCT name, priority FROM t WHERE priority = ?) t1
ON t0.name = t1.name
WHERE
t0.priority = t1.priority
OR
t1.priority IS NULL
";
mysql> EXECUTE stmt USING #priority;
+----+-------+--------+----------+
| id | name | value | priority |
+----+-------+--------+----------+
| 2 | name1 | valueX | 1 |
| 3 | name2 | value2 | NULL |
| 4 | name3 | value3 | NULL |
+----+-------+--------+----------+
3 rows in set (0.00 sec)
(Note that I changed the prioritized value of "name1" to "valueX" in the above -- your original formulation had identical value values for "name1" regardless of priority, which made it hard for me to understand why you cared to discriminate one from the other.)