MySQLServer: Check if conditions exist in group, then label entire group - sql-server

My goal is to add another column to an existing table, to see if the value/conditions exists in a group and appropriately labeling the entire group if it is present or not.
If a Team has one project with a budget >= 20M or Actual_Spend >=2.5M I want to label the Team and all it's projects as Table 1 in the Category column. Irrespective if the other projects within the same Team fit this criteria.
I will provide a SQL fiddle link w/ my solution: http://sqlfiddle.com/#!18/3ddaf/12/0
I'm ending up with two extra columns of "Team" and "Category" and not sure how they're ending up there.
Below is the end result I'm looking for. I'm open to better solutions than the one I provided.
Thank you for your time
| Team | ProjectID | Budget | Actual_Spend | State | Category |
|------|-----------|----------|--------------|------------|----------|
| Cyan | 2 | NULL | NULL | Utah | Table 1 |
| Blue | 1 | NULL | 3000000 | California | Table 1 |
| Cyan | 1 | 20000000 | 1000000 | Utah | Table 1 |
| Blue | 2 | 22000000 | NULL | California | Table 1 |
| Red | 1 | 7000000 | 1000000 | Washington | Table 2 |
| Red | 2 | 19999000 | 2490000 | Oregon | Table 2 |
| Gray | 1 | 19000000 | 2500000 | Utah | Table 1 |
| Gray | 1 | 10000000 | 500000 | Utah | Table 1 |
Providing code to create the dataset:
Create Table Source_Data
(
Team varchar(50),
ProjectID INT,
BUDGET INT,
Actual_Spend INT,
State varchar(max),
)
INSERT INTO Source_Data
VALUES
('Blue',1,NULL,3000000,'California'),
('Green',1,20000000,1000000,'Utah'),
('Blue',2,22000000,NULL,'California'),
('Green',2,NULL,NULL,'Utah'),
('Red',1,7000000,1000000,'Washington'),
('Red',2,19999000,2490000,'Oregon'),
('Yellow',1,19000000,2500000,'Utah'),
('Yellow',1,10000000,500000,'Utah');

I think that you are looking for window functions:
select
s.*,
min(case when Budget>=20000000 or Actual_Spend>=2500000 then 'Table1' else 'Table2' end)
over(partition by team) Category
from Source_Data s
If any of the records having the same team satisfies condition Budget>=20000000 or Actual_Spend>=2500000, the new column yields Table1, else it produces Table2.
Demo on DB Fiddle:
Team | ProjectID | Budget | Actual_Spend | State | Category
:--- | --------: | -------: | -----------: | :--------- | :-------
Blue | 2 | 22000000 | null | California | Table1
Blue | 1 | null | 3000000 | California | Table1
Cyan | 1 | 20000000 | 1000000 | Utah | Table1
Cyan | 2 | null | null | Utah | Table1
Gray | 1 | 19000000 | 2500000 | Utah | Table1
Gray | 1 | 10000000 | 500000 | Utah | Table1
Red | 1 | 7000000 | 1000000 | Washington | Table2
Red | 2 | 19999000 | 2490000 | Oregon | Table2

Related

Update sqlite table with non-null values from another table

I have two sqlite tables, both with the same column layout. I would like to merge the two tables (or update table 1), taking values from table 2 if they are not null, otherwise, taking them from table 1. Is there a better way of doing this this short of an UPDATE with multiple case clauses (similar to the approach in SQLITE UPDATE field IF NULL from another table)? The tables have a large number of columns which would make such a statement quite long.
table 1
|-------+-------+--------+----+--------|
| id | col1 | col2 | .. | col100 |
|-------+-------+--------+----+--------|
| 2346a | apple | red | | WA |
| d27d7 | pear | green | | VA |
| 568ba | lemon | yellow | | CA |
| 9896f | grape | purple | | CA |
| 1b7da | peach | pink | | CA |
|-------+-------+--------+----+--------|
table 2
|-------+-------+--------+----+--------|
| id | col1 | col2 | .. | col100 |
|-------+-------+--------+----+--------|
| 2346a | null | green | | null |
| 1b7da | null | null | | GA |
| 9896f | plum | null | | null |
|-------+-------+--------+----+--------|
desired result
|-------+-------+--------+----+--------|
| id | col1 | col2 | .. | col100 |
|-------+-------+--------+----+--------|
| 2346a | apple | green | | WA |
| d27d7 | pear | green | | VA |
| 568ba | lemon | yellow | | CA |
| 9896f | plum | purple | | CA |
| 1b7da | peach | pink | | GA |
|-------+-------+--------+----+--------|
You can bring table2 with a left join and prioritize non-null values from table2 using coalesce():
select
t1.id,
coalesce(t2.col1, t1.col1) col1,
coalesce(t2.col2, t1.col2) col2,
...
coalesce(t2.col100, t1.col100) col100
from table1 t1
left join table2 t2 on t2.id = t1.id
You can use ROW VALUES to update Table1:
update Table1
set (col1, col2, col100) = (
select
coalesce(t2.col1, Table1.col1),
coalesce(t2.col2, Table1.col2),
................................
coalesce(t2.col100, Table1.col100)
from Table2 t2
where t2.id = Table1.id
)
where exists (select 1 from Table2 t2 where t2.id = Table1.id);
See the demo.
Results:
| id | col1 | col2 | col100 |
| ----- | ----- | ------ | ------ |
| 2346a | apple | green | WA |
| d27d7 | pear | green | VA |
| 568ba | lemon | yellow | CA |
| 9896f | plum | purple | CA |
| 1b7da | peach | pink | GA |

Update table combining rows based on the same column value

I'm having a table called table such that:
| id | name | city |
|----|-------|---------|
| 0 | Rose | Madrid |
| 1 | Alex | Lima |
| 2 | Rose | Sidney |
| 3 | Mario | Glasgow |
And I need to UPDATE the table so that two rows sharing the same name combined into a new one and deleted.
| id | name | city |
|----|-------|----------------|
| 1 | Alex | Lima |
| 3 | Mario | Glasgow |
| 4 | Rose | Madrid, Sidney |
I don't care if it has to be done in several SQL statements.
So far all I've done is to list the rows that are affected by this.
SELECT *
FROM table
WHERE name IN (
SELECT name
FROM table
GROUP BY name
HAVING COUNT(*) > 1
);
Assuming that id is auto increment primary key, you need an INSERT and a DELETE statement:
insert into tablename(name, city)
select name, group_concat(city, ',')
from tablename
group by name
having count(*) > 1;
delete from tablename
where instr(name, ',') = 0
and exists (
select 1 from tablename t
where t.id <> tablename.id and t.name = tablename.name
and ',' || t.city || ',' like '%,' || tablename.city || ',%'
);
See the demo.
Results:
| id | name | city |
| --- | ----- | ------------- |
| 1 | Alex | Lima |
| 3 | Mario | Glasgow |
| 4 | Rose | Madrid,Sidney |

Find the newest entry of a crosstable per record?

I have three tables:
My products with their IDs and their features.
is a table with treatments of my products with a treatment-ID, a method, and a date. The treatments are done in batches of many products so there is a crosstable
with the products IDs and the treatment IDs and a bool value for the success of the treatment.
Each product can undergo many different treatments so there is a many-to-many relation. I now want to add to the product table (1.) for every product a value that shows the method of its most recent successful treatment if there is any.
I made a query that groups the crosstable's entries by product-ID but I don't know how to show the method and date of it's last treatment.
table 1:
| productID | size | weight | height | ... |
|-----------|:----:|-------:|--------|-----|
| 1 | 13 | 16 | 9 | ... |
| 2 | 12 | 17 | 12 | ... |
| 3 | 11 | 15 | 15 | ... |
| ... | ... | ... | ... | ... |
table 2:
| treatmentID | method | date |
|-------------|:--------:|-----------:|
| 1 | dye blue | 01.02.2016 |
| 2 | dye red | 01.02.2017 |
| 3 | dye blue | 01.02.2018 |
| ... | ... | ... |
table 3:
| productID | treatmentID | success |
|-----------|:-----------:|--------:|
| 1 | 1 | yes |
| 1 | 2 | yes |
| 1 | 3 | no |
| ... | ... | ... |
I need table 1 to be like:
table 1:
| productID | size | weight | height | latest succesful method |
|-----------|:----:|-------:|--------|-------------------------|
| 1 | 13 | 16 | 9 | dye red |
| 2 | 12 | 17 | 12 | ... |
| 3 | 11 | 15 | 15 | ... |
| ... | ... | ... | ... | ... |
My query:
SELECT table3.productID, table2.method
FROM table2 INNER JOIN table3 ON table2.treatmentID = table3.treatmentID
GROUP BY table3.productID, table2.method
HAVING (((table3.productID)=Max([table2].[date])))
ORDER BY table3.productID DESC;
but this does NOT show only one (the most recent) entry but all of them.
Simplest solution here would be to write either a subquery within your sql, or create a new query to act as a subquery(it will look like a table) to help indicate(or elminate) the records you want to see.
Using similar but potentially slightly different source data as you only gave one example.
Table1
| ProductID | Size | Weight | Height |
|-----------|------|--------|--------|
| 1 | 13 | 16 | 9 |
| 2 | 12 | 17 | 12 |
| 3 | 11 | 15 | 15 |
Table2
| TreatmentID | Method | Date |
|-------------|------------|----------|
| 1 | dye blue | 1/2/2016 |
| 2 | dye red | 1/2/2017 |
| 3 | dye blue | 1/2/2018 |
| 4 | dye yellow | 1/4/2017 |
| 5 | dye brown | 1/5/2018 |
Table3
| ProductID | TreatmentID | Success |
|-----------|-------------|---------|
| 1 | 1 | yes |
| 1 | 2 | yes |
| 1 | 3 | no |
| 2 | 4 | no |
| 2 | 5 | yes |
First order of business is to get the max(dates) and productIds of successful treatments.
We'll do this by aggregating the date along with the productIDs and "success".
SELECT Table3.productid, Max(Table2.Date) AS MaxOfdate, Table3.success
FROM Table2 INNER JOIN Table3 ON Table2.treatmentid = Table3.treatmentid
GROUP BY Table3.productid, Table3.success;
This should give us something along the lines of:
| ProductID | MaxofDate | Success |
|-----------|-----------|---------|
| 1 | 1/2/2018 | No |
| 1 | 1/2/2017 | Yes |
| 2 | 1/4/2017 | No |
| 2 | 1/8/2017 | Yes |
We'll save this query as a "regular" query. I named mine "max", you should probably use something more descriptive. You'll see "max" in this next query.
Next we'll join tables1-3 together but in addition we will also use this "max" subquery to link tables 1 and 2 by the productID and MaxOfDate to TreatmentDate where success = "yes" to find the details of the most recent SUCCESSFUL treatment.
SELECT table1.productid, table1.size, table1.weight, table1.height, Table2.method
FROM ((table1 INNER JOIN [max] ON table1.productid = max.productid)
INNER JOIN Table2 ON max.MaxOfdate = Table2.date) INNER JOIN Table3 ON
(Table2.treatmentid = Table3.treatmentid) AND (table1.productid = Table3.productid)
WHERE (((max.success)="yes"));
The design will look something like this:
Design
(ps. you can add queries to your design query editor by clicking on the "Queries" tab when you are adding tables to your query design. They act just like tables, just be careful as very detailed queries tend to bog down Access)
Running this query should give us our final results.
| ProductID | Size | Weight | Height | Method |
|-----------|------|--------|--------|-----------|
| 1 | 13 | 16 | 9 | dye red |
| 2 | 12 | 17 | 12 | dye brown |

I made stored procedure, but I don't know what to put on my WHERE clause to filter the null column

I made a INNER JOIN in stored procedure, but I don't know what to put to my WHERE clause to filter those column with null values and only shows those rows who has not null on a particular column.
CREATE PROCEDURE [dbo].[25]
#param1 int
AS
SELECT c.Name, c.Age, c2.Name, c2.Country
FROM Cus C
INNER JOIN Cus2 C2 ON c.id = c2.id
WHERE c2.country is not null and c2.id = #param1
Order by c2.Country
RETURN 0
ID 1
+-----+----+---------+---------+
| QID | ID | Name | Country |
+-----+----+---------+---------+
| 1 | 1 | Null | PH |
| 2 | 1 | Null | CN |
| 3 | 1 | Japhet | USA |
| 4 | 1 | Abegail | UK |
| 5 | 1 | Norlee | Ger |
+-----+----+---------+---------+
ID 2
+-----+----+----------+---------+
| QID | ID | Name | Country |
+-----+----+----------+---------+
| 1 | 2 | Null | PH |
| 2 | 2 | Null | CN |
| 3 | 2 | Reynaldo | USA |
| 4 | 2 | Abegail | UK |
| 5 | 2 | Norlee | Ger |
+-----+----+----------+---------+
ID 3
+-----+----+----------+---------+
| QID | ID | Name | Country |
+-----+----+----------+---------+
| 1 | 3 | Gab | PH |
| 2 | 3 | Null | CN |
| 3 | 3 | Reynaldo | USA |
| 4 | 3 | Abegail | UK |
| 5 | 3 | Norlee | Ger |
+-----+----+----------+---------+
I want when I choose any of the user in the C Table it will display the C child table data and remove the null name rows and remain the rows with not null name column.
Desired Result:
C Table (Parent)
+----+---------+-----+
| ID | Name | Age |
+----+---------+-----+
| 3 | Abegail | 31 |
+----+---------+-----+
C2 Table (Child)
+-----+----+----------+---------+
| QID | ID | Name | Country |
+-----+----+----------+---------+
| 1 | 3 | Gab | PH |
| 3 | 3 | Reynaldo | USA |
| 4 | 3 | Abegail | UK |
| 5 | 3 | Norlee | Ger |
+-----+----+----------+---------+
WHERE column IS NOT NULL is the syntax to filter out NULL values.
Solution 1: test not null value
Example:
WHERE yourcolumn IS NOT NULL
Solution 2: test comparaison value in your where clause (comparaison substract null values)
Examples:
WHERE yourcolumn = value
WHERE yourcolumn <> value
WHERE yourcolumn in ( value)
WHERE yourcolumn not in ( value)
WHERE yourcolumn between value1 and value2
WHERE yourcolumn not between value1 and value2

joining sql views with alternate values instead of nulls

hopefully this chart makes sense...
the problem is that I have many columns in the many-many table, how can I get all the column values in a view, without doing ISNULL for each row?
(sql server 10.5)
ITEM
+------+
| ID |
|------|
| 1 |
| 2 |
| 3 |
+------+
LANGUAGE
+-------+---------+
| ID | Name |
|-------+---------|
| 1 | English |
| 2 | French |
+-------+---------+
Item Names
+----------+---------+------------+------------+
| ItemID | LangId | Name | Color |
|----------+---------+------------+------------|
| 1 | 1 | apple | red |
| 1 | 2 | pomme | rouge |
| 2 | 1 | orange | orange |
| 3 | 1 | bannana | yellow |
+----------+---------+------------+------------+
desired view
+----------+---------+------------+------------+
| ItemID | LangId | Name | Color |
|----------+---------+------------+------------|
| 1 | 1 | apple | red |
| 1 | 2 | pomme | rouge |
| 2 | 1 | orange | orange |
| 2 | 2 | orange | orange | <--- added automatically
| 3 | 1 | bannana | yellow |
| 3 | 2 | bannana | yellow | <--- added automatically
+----------+---------+------------+------------+
because I'm trying to create a view there are certain limitations:
The columns being modified in the view must directly reference the underlying data in the table columns. The columns cannot be derived in any other way, such as through the following:
An aggregate function: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR, and VARP.
A computation. The column cannot be computed from an expression that uses other columns. Columns that are formed by using the set operators UNION, UNION ALL, CROSSJOIN, EXCEPT, and INTERSECT amount to a computation and are also not updatable.
I an however create multiple views, which is how I've gotten around some of these restrictions before. we can assume that I already have this table
intermediary view:
+----------+---------+------------+------------+
| ItemID | LangId | Name | Color |
|----------+---------+------------+------------|
| 1 | 1 | apple | red |
| 1 | 2 | pomme | rouge |
| 2 | 1 | orange | orange |
| 3 | 1 | bannana | yellow |
+----------+---------+------------+------------+
as well as:
+----------+---------+------------+------------+
| ItemID | LangId | Name | Color |
|----------+---------+------------+------------|
| 1 | 1 | apple | red |
| 1 | 2 | pomme | rouge |
| 2 | 1 | orange | orange |
| 2 | 2 | - | - |
| 3 | 1 | bannana | yellow |
| 3 | 2 | - | - |
+----------+---------+------------+------------+
these are some of the views:
view1 - all combinations
view2 - all combinations with languages
the corresponding SQL:
SELECT dbo.view1.ItemID, dbo.view1.LanguageID, dbo.ItemLanguages.Name, dbo.ItemLanguages.Color
FROM dbo.ItemLanguages RIGHT OUTER JOIN
dbo.view1 ON dbo.ItemLanguages.LanguageID = dbo.view1.LanguageID AND dbo.ItemLanguages.ItemID = dbo.view1.ItemID
result of view 2
here is the test database with the views and tables: http://pastebin.com/4BpBSmHY
One way I've been able to do it is using ISNULL
SELECT dbo.view1.ItemID,
dbo.view1.LanguageID,
ISNULL(dbo.ItemLanguages.Name,
(SELECT TOP (1) Name
FROM dbo.ItemLanguages AS x
WHERE (ItemID = dbo.view1.ItemID))) AS Name,
ISNULL(dbo.ItemLanguages.Color,
(SELECT TOP (1) Color
FROM dbo.ItemLanguages AS x
WHERE (ItemID = dbo.view1.ItemID))) AS Color,
CASE
WHEN dbo.ItemLanguages.ItemID is NULL THEN 1
ELSE 0
END as valid
FROM dbo.ItemLanguages RIGHT OUTER JOIN
dbo.view1 ON dbo.ItemLanguages.ItemID = dbo.view1.ItemID
AND dbo.ItemLanguages.LanguageID = dbo.view1.LanguageID
the reason why I don't like this approach is that I'm doing this across many more columns. I have the notion that doing multiple SELECTS would slow down the result drastically.
I though I'd be able to just check if the row exists like with the CASE
WHEN dbo.ItemLanguages.ItemID is NULL THEN 1
ELSE 0
END as valid
and then call the select once and populate all the columns
.. in a view

Resources