I have p1 and p2 in my db and a variable $product.
$product can either be in p1 or p2 but not both.
Not sure if this what I should be using:
$criteria->addColumnCondition(array('p1'=>$prod_id, 'p2'=>$prod_id),'OR');
Only p1 shows correctly, and p2 doesn't display anything. p2 should show exactly like p1.
Related
I Have three columns(say P1,P2,P3) in a table. how to compare(P2<P3<P1) if is true return '1' else '0'.. how can i write SQL query for this scenario
if you are using mysql, you can try the IF function.
select IF(P1 > P3 and P3> P2, '1', '0') as r from table;
To do this you need use CASE ... END.
SELECT
P1,
P2,
P3,
CASE
WHEN P2 < P3 AND P3 < P1 THEN 1
ELSE 0
END AS Result
FROM Table;
For each row, SQL will evaluate the condition in the WHEN clause and use the result programmed in the THEN clause. You can have many WHEN conditions if you need something more complex. If none of the WHEN clauses is true, it will display the value for ELSE.
In the example above, I just added P1, P2, P3 so you can better see how it just work as another column in the query, but they are not required for CASE to work.
More examples:
https://www.w3schools.com/sql/sql_case.asp
I have a data problem I need to clean up. Basically I have two tables storing "package" information, one table for documents and one table for audit information. I have entries in the package tables that reference documents that no longer exist and have been replaced (same name but different id) and I want to write a query to find all the bad ones and which new document should replace them. The only thing linking these two is a string value in the audit table which stores the document name (not id).
I've setup a sample schema here: http://sqlfiddle.com/#!4/997bda/1
package_s is the single values for a package in our application
package_r is the repeating values for a package in our application
(these are joined with the same value in the id column)
audit_info is all the audit information in a package
docs is all the documents that can be attached to a package
This query finds the packages with bad attachments (may be more than one per package)
select distinct ps.pkgname, pr.doc_list
from package_s ps, package_r pr
where ps.id = pr.id
and not exists (
select 1 from docs
where pr.doc_list = id
)
order by 1,2 asc
;
I need to build a query with the following rules:
I need to return at least the package id, the position value and the new document id (I will build an update statement to put this new document id in the row matching the package id / position in the package_r table)
the way to get the document name from the audit information is:
SUBSTR(description,0,INSTR(description,'[')-2)
If the document was Added and then Removed, it should be ignored (string_1)
string_2 must not be 'Supporting'
the new document must match
state = 'Master'
latest = 1
pub = '0'
Right now I have a semi-working script that works on a per package basis, but the problem is affecting 2000+ packages. I find the audit entries that don't match documents correctly attached to the package and then search for those names in the document table. The problem with this is since there is no direct link between the package and document tables, if there are multiple problem attachments on one package, each "new" document is returned once per position value, i.e.
package id bad doc id position new doc id
p1 d1 -1 d1-new
p1 d1 -1 d4-new
p1 d4 -2 d1-new
p1 d4 -2 d4-new
It doesn't matter which new id goes into which position value, but the duplication result problem like this makes it hard to mass generate update scripts, some manual filtering would be required.
This is a somewhat complex and unique data issue, so any help would be greatly appreciated.
This query works according to informations provided:
with ai as (
select a1.audited_id id, dc.id doc_id, dc.docname,
row_number() over (partition by a1.audited_id order by dc.id) rn
from audit_info a1
join docs dc
on dc.state = 'Master' and dc.latest = 1 and dc.pub = '0'
and dc.docname = substr(a1.description, 1, instr(a1.description, '[')-2)
where string_1 = 'Added' and string_2 <> 'Supporting'
and not exists (
select * from audit_info a2
where a2.audited_id = a1.audited_id and string_1 = 'Removed'
and a2.description = a1.description )
and not exists ( -- here matching docs are eliminated
select 1 from package_r pr
where pr.id = a1.audited_id and pr.doc_list = dc.id ) ),
p as (
select ps.id, ps.pkgname, pr.doc_list, pr.position,
row_number() over (partition by ps.id order by doc_list) rn
from package_s ps
join package_r pr on pr.id = ps.id
where not exists ( select * from docs where pr.doc_list = docs.id )
)
select p.id, p.pkgname, p.doc_list, p.position
, ai.docname, ai.doc_id
from p join ai on ai.id = p.id and p.rn = ai.rn
order by p.id, p.doc_list, ai.doc_id
Output:
ID PKGNAME DOC_LIST POSITION DOCNAME DOC_ID
-- ------- -------- -------- ------- ------
p1 000001 d3 -3 doc3 d3-new
p1 000001 d4 -4 doc4 d4-new
p2 000002 d5 -2 doc5 d5-new
p4 000004 d6 -1 doc6 d6-new
Edit: Answers to issues reported in comments
it is identifying packages that do not have bad values, and then the doc_list column is blank,
Note that query (my subquery p) for identyfing packages is basically your query, I just added counter there.
I guess that some process/application or someone manually cleared column doc_list in package_r.
If you don't want such entries, just add condition and trim(doc_list) is not null in subquery p.
for the ones it gets right on the package part (they have a bad value) it is bringing back the wrong docname/doc_id to replace the bad value with, it is a different doc_id in the list.
I understand this only partially. Can you add such entries to your examples (in Fiddle or just edit your question and add problematic input rows and expected output for them?)
"It doesn't matter which new id goes into which position value".
Assignment I made this way - if we had two old docs with names "ABC", "DEF" and corrected docs have names "XXA", "DE12"
then they will be linked as "ABC"->"DE12" and "DEF"->"XXA" (alphabetical ordering seems more rational than totally random).
To make assigning random change order by ... to order by null in both row_number() functions.
I need to use either SQL or Excel to copy the picture columns data of the other corresponding picture values for the SAME model and color when the field is NULL.
For this picture shown I need D-2 and D-4 to also say A-2.jpg instead of NULL
(It's the same A model and the color is red so copy the existing A model and red picture that's there). I need D-7 to either copy D-5 or D-6's picture value (A-4.jpg or A-5.jpg would work). So on.... If there are not particular pictures for that group (ie. model B and Black) then it can be left as NULL.
I'm trying to use group by functions and nested selects, but I am getting nowhere with this.
If you are using MS SQL Server, you can use a self join to update the table.
update r set r.picture = l.picture
from Item l
join Item r on l.model = r.model and l.color=r.color
where
l.picture is not null and
r.picture is null
Assuming your table is called "products" you might be able to do something like this:
UPDATE products p SET picture = (
SELECT picture
FROM products p2
WHERE p2.model = p.model
AND p2.color = p.model
)
WHERE p.picture IS NULL
The rules about update commands vary between different Database systems. Let us know which database you are using if the above query does not work.
I want to find list of entities that are present in the first list and reject entities if they exists in second list.
Example data:
I've got Products: P1,P2 and P3. Another (main) entity is Items: I1 and I2. I1 entity contains P1, and P2 and I2 contains P2 and P3. I want to find list of Items, if they're present in List1(contains just P1) and reject every Item if it's present in List2(contains just P3). So it should give me I1 as output.
My query and code:
Query query = this.em.createQuery("SELECT distinct(i) FROM Item i join fetch i.products ip WHERE ip.product IN :list1 AND ip.product NOT IN :list2");
query.setParameter("list1", list1);
query.setParameter("list2", list2);
This query gives me list of both Items. What's wrong here?
Try this
SELECT distinct i FROM Item i join fetch i.products ip WHERE :list1 IN ip and :list2 NOT IN ip
UPDATE
I've been trying to get this to work myself, but with no results. #NeilStockton suggested it is not supported in JPA specification.
However, in your example you have parameter lists with one element. In case of single element parameters, this should work:
Query query = this.em.createQuery("SELECT distinct i FROM Item i join fetch i.products ip WHERE :param1 IN elements(ip) and :param2 NOT IN elements(ip)");
query.setParameter("param1", product1);
query.setParameter("param2", product2);
Table Parent
Column1
S1
S2
S3
Table Child
Column1 Column2
S1 P1
S1 P2
S2 P1
S2 P2
S3 P1
Where parent.column1 = child.column1
Given the above tables, I need to identify the parents whose children have the same records in column2 as parent S1 does.
For example, S1 and S2 both have P1 and P2, so that would meet the condition. S3, however, does not have P2, and should therefore be excluded.
New to SQL, so I'm having some trouble. Tried it by using a not in statement, but since S3 has P1, it's not being excluded.
You need a join. This will vary by SQL dialect. Something like:
select child.column1, child.column2 from (
select column2 as parentsColumn2Value from child where column1='S1'
) as parentsColumn2Table
left join child on parentsColumn2Table.column2=child.column2
Solving this for the general case of finding all the matching parents is more fun :) See note at the bottom for how this can be used for the simpler case (one of the parent keys is fixed).
I'll give what I think is a "proper" solution, but I don't have a copy of Access (or SQL Server) to hand to see if it works in there. (Yes, I have tested this against a DB here though...)
SELECT p1.column1, p2.column1
FROM parent p1 JOIN parent p2 ON p1.column1 < p2.column1
WHERE NOT EXISTS (SELECT 1
FROM (SELECT c1.column1, c1.column2 FROM child c1 WHERE c1.column1 = p1.column1) c1f
FULL OUTER JOIN
(SELECT c2.column1, c2.column2 FROM child c2 WHERE c2.column1 = p2.column1) c2f
ON c1f.column2 = c2f.column2
WHERE c1f.column1 IS NULL OR c2f.column1 IS NULL
);
So hopefully you can see how what I said above is tied together in this :) I'll try to explain...
The "outer" (first) select generates combinations of column1 values (p1.column1 and p2.column1). For each of the combinations, we list the rows in "child" for those values (these are c1f and c2f: c1f means "child 1 filtered") and do a FULL OUTER JOIN. Which is a comparatively rare construct, in my experience. We want to match up all the entries in c1f and c2f (using their column1 values), and find any on either side that doesn't have a corresponding entry on the other side. If there are any such non-matchers then they will manifest as rows from the join with a null for their column1 value. So the parent query selects only combinations of column1 values where no such rows in the subquery exist, i.e. every child row for p1's column1 value has a corresponding child row for p2's column1 value and vice versa.
So for instance, for the iteration where p1.column1 is 'S1' and p2.column2 is 'S3', that subquery (without aggregation) would produce:
c1f__column1 | c1f__column2 | c2f__column1 | c2f__column2
--------------+--------------+--------------+--------------
S1 | P1 | S3 | P1
S1 | P2 | |
and it's those nulls in the second row that flag this combination as not matching. Some twisty thinking involved, it's tempting to get fixated on finding matching combinations, when finding non-matching ones is easier.
As a final bonus, when I created some test tables for this, I made (column1,column2) the primary key of child, which just so happened to be exactly what you need to drive the full outer join of the filtered tables efficiently. Win! (So do note I haven't tried to cope with duplicate combinations in child... but you could just slap "distinct" in the c1f and c2f derivations)
NB based on Matt's comment, if one of your parent values was known (i.e. you just wanted to list all the parent values with the same children as S1) then you can just slap "and p1.column1 = 'S1'" on the end of this. But replace "parent p1 JOIN parent p2 ON p1.column1 < p2.column1" with just "parent p1, parent p2" in that case... remember that otherwise the query as written will only output half of all the possible pairs...
This is an Access, rather than an SQL solution in that it makes use of a User Defined Function (UDF).
SELECT p.Column1,
ConcatList("SELECT Column2 FROM c WHERE Column1='S1'","|") AS S1,
ConcatList("SELECT Column2 FROM c WHERE Column1='" & [p].[Column1] & "'","|") AS Child,
Format([S1]=[Child],"Yes/No") AS [Match]
FROM p;
The UDF
Function ConcatList(strSQL As String, strDelim, ParamArray NameList() As Variant)
''Reference: Microsoft DAO x.x Object Library
Dim db As Database
Dim rs As DAO.Recordset
Dim strList As String
Set db = CurrentDb
If strSQL <> "" Then
Set rs = db.OpenRecordset(strSQL)
Do While Not rs.EOF
strList = strList & strDelim & rs.Fields(0)
rs.MoveNext
Loop
strList = Mid(strList, Len(strDelim) + 1)
Else
strList = Join(NameList, strDelim)
End If
ConcatList = strList
End Function
Unfortunately, I do not believe Jet supports Full Outer Join, so a solution using only SQL is likely to be a little tedious, and require more information, such as whether S1 has a fixed number of entries in column2.
ACE/Jet may not support FULL OUTER JOIN directly but the workaround is simple enough i.e. just UNION ALL the LEFT JOIN, INNER JOIN and RIGHT JOIN respectively of the tables.
Incidentally, i was searching for the same solution and have figured it out myself
select * from TableParent where id in
(select temp_parent.id from
(select TableParent.*, count(exact_match.match_count) as exact_count
from TableParent
inner join
(select Column1, count(*) as match_count from TableChild
group by Column1
having match_count = 2
) as exact_match on exact_match.Column1 = TableParent.Column1
inner join
TableChild on TableChild.event_id = exact_match.Column1 where TableChild.Column2 in (P1,P2)
group by TableParent.Column1
having exact_count = 2) as temp_parent)